diff options
| author | eeeee <eeeee@qwe123.info> | 2015-02-07 14:15:19 -0800 |
|---|---|---|
| committer | def <dennis@felsin9.de> | 2015-04-19 16:05:13 +0200 |
| commit | 424ce4987ced7deda3e355b7b6373680bf506646 (patch) | |
| tree | 239537b1938ac18c6542a05088bc26c6a2860408 | |
| parent | 9bbe115c522835c34c29196f2595c29c6bf00701 (diff) | |
| download | zcatch-424ce4987ced7deda3e355b7b6373680bf506646.tar.gz zcatch-424ce4987ced7deda3e355b7b6373680bf506646.zip | |
added libwebsockets source code
26 files changed, 11789 insertions, 0 deletions
diff --git a/src/engine/external/libwebsockets/LICENSE b/src/engine/external/libwebsockets/LICENSE new file mode 100644 index 00000000..7c898655 --- /dev/null +++ b/src/engine/external/libwebsockets/LICENSE @@ -0,0 +1,526 @@ +Libwebsockets and included programs are provided under the terms of the GNU +Library General Public License (LGPL) 2.1, with the following exceptions: + +1) Static linking of programs with the libwebsockets library does not +constitute a derivative work and does not require the author to provide +source code for the program, use the shared libwebsockets libraries, or +link their program against a user-supplied version of libwebsockets. + +If you link the program to a modified version of libwebsockets, then the +changes to libwebsockets must be provided under the terms of the LGPL in +sections 1, 2, and 4. + +2) You do not have to provide a copy of the libwebsockets license with +programs that are linked to the libwebsockets library, nor do you have to +identify the libwebsockets license in your program or documentation as +required by section 6 of the LGPL. + +However, programs must still identify their use of libwebsockets. The +following example statement can be included in user documentation to +satisfy this requirement: + +"[program] is based in part on the work of the libwebsockets project +(http://libwebsockets.org)" + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/src/engine/external/libwebsockets/alloc.c b/src/engine/external/libwebsockets/alloc.c new file mode 100644 index 00000000..3bc5260e --- /dev/null +++ b/src/engine/external/libwebsockets/alloc.c @@ -0,0 +1,30 @@ +#include "private-libwebsockets.h" + +static void *_realloc(void *ptr, size_t size) +{ + if (size) + return realloc(ptr, size); + else if (ptr) + free(ptr); + return NULL; +} + +void *(*_lws_realloc)(void *ptr, size_t size) = _realloc; + +void *lws_realloc(void *ptr, size_t size) +{ + return _lws_realloc(ptr, size); +} + +void *lws_zalloc(size_t size) +{ + void *ptr = _lws_realloc(NULL, size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void lws_set_allocator(void *(*cb)(void *ptr, size_t size)) +{ + _lws_realloc = cb; +} diff --git a/src/engine/external/libwebsockets/base64-decode.c b/src/engine/external/libwebsockets/base64-decode.c new file mode 100644 index 00000000..92501b03 --- /dev/null +++ b/src/engine/external/libwebsockets/base64-decode.c @@ -0,0 +1,185 @@ +/* + * This code originally came from here + * + * http://base64.sourceforge.net/b64.c + * + * with the following license: + * + * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * VERSION HISTORY: + * Bob Trower 08/04/01 -- Create Version 0.00.00B + * + * I cleaned it up quite a bit to match the (linux kernel) style of the rest + * of libwebsockets; this version is under LGPL2 like the rest of libwebsockets + * since he explictly allows sublicensing, but I give the URL above so you can + * get the original with Bob's super-liberal terms directly if you prefer. + */ + + +#include <stdio.h> +#include <string.h> +#include "private-libwebsockets.h" + +static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW" + "$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +LWS_VISIBLE int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size) +{ + unsigned char triple[3]; + int i; + int len; + int line = 0; + int done = 0; + + while (in_len) { + len = 0; + for (i = 0; i < 3; i++) { + if (in_len) { + triple[i] = *in++; + len++; + in_len--; + } else + triple[i] = 0; + } + + if (done + 4 >= out_size) + return -1; + + *out++ = encode[triple[0] >> 2]; + *out++ = encode[((triple[0] & 0x03) << 4) | + ((triple[1] & 0xf0) >> 4)]; + *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) | + ((triple[2] & 0xc0) >> 6)] : '='); + *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '='); + + done += 4; + line += 4; + } + + if (done + 1 >= out_size) + return -1; + + *out++ = '\0'; + + return done; +} + +/* + * returns length of decoded string in out, or -1 if out was too small + * according to out_size + */ + +LWS_VISIBLE int +lws_b64_decode_string(const char *in, char *out, int out_size) +{ + int len; + int i; + int done = 0; + unsigned char v; + unsigned char quad[4]; + + while (*in) { + + len = 0; + for (i = 0; i < 4 && *in; i++) { + + v = 0; + while (*in && !v) { + + v = *in++; + v = (v < 43 || v > 122) ? 0 : decode[v - 43]; + if (v) + v = (v == '$') ? 0 : v - 61; + if (*in) { + len++; + if (v) + quad[i] = v - 1; + } else + quad[i] = 0; + } + } + + if (out_size < (done + len - 1)) + /* out buffer is too small */ + return -1; + + if (len >= 2) + *out++ = quad[0] << 2 | quad[1] >> 4; + if (len >= 3) + *out++ = quad[1] << 4 | quad[2] >> 2; + if (len >= 4) + *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; + + done += len - 1; + } + + if (done + 1 >= out_size) + return -1; + + *out++ = '\0'; + + return done; +} + +int +lws_b64_selftest(void) +{ + char buf[64]; + int n; + int test; + static const char * const plaintext[] = { + "sanity check base 64" + }; + static const char * const coded[] = { + "c2FuaXR5IGNoZWNrIGJhc2UgNjQ=" + }; + + for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) { + + buf[sizeof(buf) - 1] = '\0'; + n = lws_b64_encode_string(plaintext[test], + strlen(plaintext[test]), buf, sizeof buf); + if (n != strlen(coded[test]) || strcmp(buf, coded[test])) { + lwsl_err("Failed lws_b64 encode selftest " + "%d result '%s' %d\n", test, buf, n); + return -1; + } + + buf[sizeof(buf) - 1] = '\0'; + n = lws_b64_decode_string(coded[test], buf, sizeof buf); + if (n != strlen(plaintext[test]) || + strcmp(buf, plaintext[test])) { + lwsl_err("Failed lws_b64 decode selftest " + "%d result '%s' %d\n", test, buf, n); + return -1; + } + } + + return 0; +} diff --git a/src/engine/external/libwebsockets/config.h b/src/engine/external/libwebsockets/config.h new file mode 100644 index 00000000..617c897b --- /dev/null +++ b/src/engine/external/libwebsockets/config.h @@ -0,0 +1,174 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef WIN32 +/* #undef _DEBUG */ +#endif + +/* Define to 1 to use CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +/* #undef USE_CYASSL */ + +/* The Libwebsocket version */ +#define LWS_LIBRARY_VERSION "1.3" + +/* The current git commit hash that we're building from */ +#define LWS_BUILD_HASH "080e6dd" + +/* Build with OpenSSL support */ +/* #undef LWS_OPENSSL_SUPPORT */ + +/* The client should load and trust CA root certs it finds in the OS */ +/* #undef LWS_SSL_CLIENT_USE_OS_CA_CERTS */ + +/* Sets the path where the client certs should be installed. */ +#define LWS_OPENSSL_CLIENT_CERTS "../share" + +/* Turn off websocket extensions */ +/* #undef LWS_NO_EXTENSIONS */ + +/* Enable libev io loop */ +/* #undef LWS_USE_LIBEV */ + +/* Build with support for ipv6 */ +/* #undef LWS_USE_IPV6 */ + +/* Build with support for HTTP2 */ +/* #undef LWS_USE_HTTP2 */ + +/* Turn on latency measuring code */ +/* #undef LWS_LATENCY */ + +/* Don't build the daemonizeation api */ +#define LWS_NO_DAEMONIZE + +/* Build without server support */ +/* #undef LWS_NO_SERVER */ + +/* Build without client support */ +#define LWS_NO_CLIENT + +/* If we should compile with MinGW support */ +/* #undef LWS_MINGW_SUPPORT */ + +/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ +/* #undef LWS_BUILTIN_GETIFADDRS */ + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK + +/* Define to 1 if you have the `getenv’ function. */ +#define HAVE_GETENV + +/* Define to 1 if you have the <in6addr.h> header file. */ +/* #undef HAVE_IN6ADDR_H */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H + +/* Define to 1 if you have the `ssl' library (-lssl). */ +/* #undef HAVE_LIBSSL */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#define HAVE_NETINET_IN_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +/* #undef HAVE_SYS_PRCTL_H */ + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK + +/* Define to 1 if you have the <vfork.h> header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK + +/* Define to 1 if you have the <zlib.h> header file. */ +#define HAVE_ZLIB_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR // We're not using libtool + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Version number of package */ +#define VERSION + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if <sys/types.h> does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if <sys/types.h> does not define. */ +/* #undef size_t */ + +/* Define to 1 if we have getifaddrs */ +#define HAVE_GETIFADDRS + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +/* Define if the inline keyword doesn't exist. */ +/* #undef inline */ diff --git a/src/engine/external/libwebsockets/context.c b/src/engine/external/libwebsockets/context.c new file mode 100644 index 00000000..2ea9c60d --- /dev/null +++ b/src/engine/external/libwebsockets/context.c @@ -0,0 +1,337 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +#ifndef LWS_BUILD_HASH +#define LWS_BUILD_HASH "unknown-build-hash" +#endif + +static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH; + +/** + * lws_get_library_version: get version and git hash library built from + * + * returns a const char * to a string like "1.1 178d78c" + * representing the library version followed by the git head hash it + * was built from + */ + +LWS_VISIBLE const char * +lws_get_library_version(void) +{ + return library_version; +} + +/** + * libwebsocket_create_context() - Create the websocket handler + * @info: pointer to struct with parameters + * + * This function creates the listening socket (if serving) and takes care + * of all initialization in one step. + * + * After initialization, it returns a struct libwebsocket_context * that + * represents this server. After calling, user code needs to take care + * of calling libwebsocket_service() with the context pointer to get the + * server's sockets serviced. This must be done in the same process + * context as the initialization call. + * + * The protocol callback functions are 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. + * + * HTTP requests are sent always to the FIRST protocol in @protocol, since + * at that time websocket protocol has not been negotiated. Other + * protocols after the first one never see any HTTP callack activity. + * + * 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. + */ + +LWS_VISIBLE struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info) +{ + struct libwebsocket_context *context = NULL; + char *p; + + int pid_daemon = get_daemonize_pid(); + + lwsl_notice("Initial logging level %d\n", log_level); + lwsl_notice("Library version: %s\n", library_version); +#ifdef LWS_USE_IPV6 + if (!(info->options & LWS_SERVER_OPTION_DISABLE_IPV6)) + lwsl_notice("IPV6 compiled in and enabled\n"); + else + lwsl_notice("IPV6 compiled in but disabled\n"); +#else + lwsl_notice("IPV6 not compiled in\n"); +#endif + lws_feature_status_libev(info); + lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN); + lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS); + + lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED); + lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT); + lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH); + lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER); + + if (lws_plat_context_early_init()) + return NULL; + + context = lws_zalloc(sizeof(struct libwebsocket_context)); + if (!context) { + lwsl_err("No memory for websocket context\n"); + return NULL; + } + + if (pid_daemon) { + context->started_with_parent = pid_daemon; + lwsl_notice(" Started with daemon pid %d\n", pid_daemon); + } + + context->listen_service_extraseen = 0; + context->protocols = info->protocols; + context->token_limits = info->token_limits; + context->listen_port = info->port; + context->http_proxy_port = 0; + context->http_proxy_address[0] = '\0'; + context->options = info->options; + context->iface = info->iface; + context->ka_time = info->ka_time; + context->ka_interval = info->ka_interval; + context->ka_probes = info->ka_probes; + + /* to reduce this allocation, */ + context->max_fds = getdtablesize(); + lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n", + sizeof(struct libwebsocket_context), + sizeof(struct libwebsocket_pollfd) + + sizeof(struct libwebsocket *), + context->max_fds, + sizeof(struct libwebsocket_context) + + ((sizeof(struct libwebsocket_pollfd) + + sizeof(struct libwebsocket *)) * + context->max_fds)); + + context->fds = lws_zalloc(sizeof(struct libwebsocket_pollfd) * + context->max_fds); + if (context->fds == NULL) { + lwsl_err("Unable to allocate fds array for %d connections\n", + context->max_fds); + lws_free(context); + return NULL; + } + + context->lws_lookup = lws_zalloc(sizeof(struct libwebsocket *) * context->max_fds); + if (context->lws_lookup == NULL) { + lwsl_err( + "Unable to allocate lws_lookup array for %d connections\n", + context->max_fds); + lws_free(context->fds); + lws_free(context); + return NULL; + } + + if (lws_plat_init_fd_tables(context)) { + lws_free(context->lws_lookup); + lws_free(context->fds); + lws_free(context); + return NULL; + } + + lws_context_init_extensions(info, context); + + context->user_space = info->user; + + strcpy(context->canonical_hostname, "unknown"); + + lws_server_get_canonical_hostname(context, info); + + /* split the proxy ads:port if given */ + + if (info->http_proxy_address) { + strncpy(context->http_proxy_address, info->http_proxy_address, + sizeof(context->http_proxy_address) - 1); + context->http_proxy_address[ + sizeof(context->http_proxy_address) - 1] = '\0'; + context->http_proxy_port = info->http_proxy_port; + } else { +#ifdef HAVE_GETENV + p = getenv("http_proxy"); + if (p) { + strncpy(context->http_proxy_address, p, + sizeof(context->http_proxy_address) - 1); + context->http_proxy_address[ + sizeof(context->http_proxy_address) - 1] = '\0'; + + p = strchr(context->http_proxy_address, ':'); + if (p == NULL) { + lwsl_err("http_proxy needs to be ads:port\n"); + goto bail; + } + *p = '\0'; + context->http_proxy_port = atoi(p + 1); + } +#endif + } + + if (context->http_proxy_address[0]) + lwsl_notice(" Proxy %s:%u\n", + context->http_proxy_address, + context->http_proxy_port); + + lwsl_notice( + " per-conn mem: %u + %u headers + protocol rx buf\n", + sizeof(struct libwebsocket), + sizeof(struct allocated_headers)); + + if (lws_context_init_server_ssl(info, context)) + goto bail; + + if (lws_context_init_client_ssl(info, context)) + goto bail; + + if (lws_context_init_server(info, context)) + goto bail; + + /* + * drop any root privs for this process + * to listen on port < 1023 we would have needed root, but now we are + * listening, we don't want the power for anything else + */ + lws_plat_drop_app_privileges(info); + + /* initialize supported protocols */ + + for (context->count_protocols = 0; + info->protocols[context->count_protocols].callback; + context->count_protocols++) { + + lwsl_parser(" Protocol: %s\n", + info->protocols[context->count_protocols].name); + + info->protocols[context->count_protocols].owning_server = + context; + info->protocols[context->count_protocols].protocol_index = + context->count_protocols; + + /* + * inform all the protocols that they are doing their one-time + * initialization if they want to + */ + info->protocols[context->count_protocols].callback(context, + NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0); + } + + /* + * give all extensions a chance to create any per-context + * allocations they need + */ + + if (info->port != CONTEXT_PORT_NO_LISTEN) { + if (lws_ext_callback_for_each_extension_type(context, NULL, + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + NULL, 0) < 0) + goto bail; + } else + if (lws_ext_callback_for_each_extension_type(context, NULL, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + NULL, 0) < 0) + goto bail; + + return context; + +bail: + libwebsocket_context_destroy(context); + return NULL; +} + +/** + * libwebsocket_context_destroy() - Destroy the websocket context + * @context: Websocket context + * + * This function closes any active connections and then frees the + * context. After calling this, any further use of the context is + * undefined. + */ +LWS_VISIBLE void +libwebsocket_context_destroy(struct libwebsocket_context *context) +{ + int n; + struct libwebsocket_protocols *protocol = context->protocols; + + lwsl_notice("%s\n", __func__); + +#ifdef LWS_LATENCY + if (context->worst_latency_info[0]) + lwsl_notice("Worst latency: %s\n", context->worst_latency_info); +#endif + + for (n = 0; n < context->fds_count; n++) { + struct libwebsocket *wsi = + context->lws_lookup[context->fds[n].fd]; + if (!wsi) + continue; + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */); + n--; + } + + /* + * give all extensions a chance to clean up any per-context + * allocations they might have made + */ + if (context->listen_port != CONTEXT_PORT_NO_LISTEN) { + if (lws_ext_callback_for_each_extension_type(context, NULL, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, NULL, 0) < 0) + return; + } else + if (lws_ext_callback_for_each_extension_type(context, NULL, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, NULL, 0) < 0) + return; + + /* + * inform all the protocols that they are done and will have no more + * callbacks + */ + + while (protocol->callback) { + protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY, + NULL, NULL, 0); + protocol++; + } + + lws_plat_context_early_destroy(context); + + lws_ssl_context_destroy(context); + + lws_free(context->fds); + lws_free(context->lws_lookup); + + lws_plat_context_late_destroy(context); + + lws_free(context); +} diff --git a/src/engine/external/libwebsockets/extension-deflate-frame.c b/src/engine/external/libwebsockets/extension-deflate-frame.c new file mode 100644 index 00000000..13b2b8de --- /dev/null +++ b/src/engine/external/libwebsockets/extension-deflate-frame.c @@ -0,0 +1,288 @@ +#include "private-libwebsockets.h" +#include "extension-deflate-frame.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define LWS_ZLIB_WINDOW_BITS 15 +#define LWS_ZLIB_MEMLEVEL 8 + +int lws_extension_callback_deflate_frame( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct lws_ext_deflate_frame_conn *conn = + (struct lws_ext_deflate_frame_conn *)user; + struct lws_tokens *eff_buf = (struct lws_tokens *)in; + size_t current_payload, remaining_payload, total_payload; + int n; + size_t len_so_far; + + switch (reason) { + + /* + * for deflate-frame, both client and server sides act the same + */ + + case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: + case LWS_EXT_CALLBACK_CONSTRUCT: + conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL; + conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL; + conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL; + n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS); + if (n != Z_OK) { + lwsl_ext("deflateInit returned %d\n", n); + return 1; + } + n = deflateInit2(&conn->zs_out, + (context->listen_port ? + DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER : + DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT), + Z_DEFLATED, + -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (n != Z_OK) { + lwsl_ext("deflateInit2 returned %d\n", n); + return 1; + } + conn->buf_pre_used = 0; + conn->buf_pre_length = 0; + conn->buf_in_length = sizeof(conn->buf_in); + conn->buf_out_length = sizeof(conn->buf_out); + conn->compressed_out = 0; + conn->buf_pre = NULL; + conn->buf_in = lws_malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_in) + goto bail; + conn->buf_out = lws_malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_out) + goto bail; + lwsl_ext("zlibs constructed\n"); + break; +bail: + lwsl_err("Out of mem\n"); + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + return -1; + + case LWS_EXT_CALLBACK_DESTROY: + lws_free(conn->buf_pre); + lws_free(conn->buf_in); + lws_free(conn->buf_out); + conn->buf_pre_used = 0; + conn->buf_pre_length = 0; + conn->buf_in_length = 0; + conn->buf_out_length = 0; + conn->compressed_out = 0; + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + lwsl_ext("zlibs destructed\n"); + break; + + case LWS_EXT_CALLBACK_PAYLOAD_RX: + if (!(wsi->u.ws.rsv & 0x40)) + return 0; + + /* + * inflate the incoming payload + */ + current_payload = eff_buf->token_len; + + remaining_payload = wsi->u.ws.rx_packet_length; + if (remaining_payload) { + total_payload = conn->buf_pre_used + + current_payload + + remaining_payload; + + if (conn->buf_pre_length < total_payload) { + conn->buf_pre_length = total_payload; + lws_free(conn->buf_pre); + conn->buf_pre = lws_malloc(total_payload + 4); + if (!conn->buf_pre) { + lwsl_err("Out of memory\n"); + return -1; + } + } + + memcpy(conn->buf_pre + conn->buf_pre_used, + eff_buf->token, current_payload); + conn->buf_pre_used += current_payload; + + eff_buf->token = NULL; + eff_buf->token_len = 0; + + return 0; + } + if (conn->buf_pre_used) { + total_payload = conn->buf_pre_used + + current_payload; + + memcpy(conn->buf_pre + conn->buf_pre_used, + eff_buf->token, current_payload); + conn->buf_pre_used = 0; + + conn->zs_in.next_in = conn->buf_pre; + } else { + total_payload = current_payload; + + conn->zs_in.next_in = (unsigned char *)eff_buf->token; + } + + conn->zs_in.next_in[total_payload + 0] = 0; + conn->zs_in.next_in[total_payload + 1] = 0; + conn->zs_in.next_in[total_payload + 2] = 0xff; + conn->zs_in.next_in[total_payload + 3] = 0xff; + + conn->zs_in.avail_in = total_payload + 4; + + conn->zs_in.next_out = + conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING; + conn->zs_in.avail_out = conn->buf_in_length; + + while (1) { + n = inflate(&conn->zs_in, Z_SYNC_FLUSH); + switch (n) { + case Z_NEED_DICT: + case Z_STREAM_ERROR: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + /* + * screwed.. close the connection... + * we will get a destroy callback to take care + * of closing nicely + */ + lwsl_info("zlib error inflate %d: %s\n", + n, conn->zs_in.msg); + return -1; + } + + if (conn->zs_in.avail_out) + break; + + len_so_far = conn->zs_in.next_out - + (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING); + + conn->buf_in_length *= 2; + if (conn->buf_in_length > LWS_MAX_ZLIB_CONN_BUFFER) { + lwsl_ext("zlib in buffer hit limit %u\n", + LWS_MAX_ZLIB_CONN_BUFFER); + return -1; + } + conn->buf_in = lws_realloc(conn->buf_in, + LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_in) { + lwsl_err("Out of memory\n"); + return -1; + } + lwsl_debug( + "deflate-frame ext RX did realloc to %ld\n", + conn->buf_in_length); + conn->zs_in.next_out = conn->buf_in + + LWS_SEND_BUFFER_PRE_PADDING + len_so_far; + conn->zs_in.avail_out = + conn->buf_in_length - len_so_far; + } + + /* rewrite the buffer pointers and length */ + eff_buf->token = + (char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING); + eff_buf->token_len = (int)(conn->zs_in.next_out - + (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING)); + + return 0; + + case LWS_EXT_CALLBACK_PAYLOAD_TX: + /* + * deflate the outgoing payload + */ + current_payload = eff_buf->token_len; + + conn->zs_out.next_in = (unsigned char *)eff_buf->token; + conn->zs_out.avail_in = current_payload; + + conn->zs_out.next_out = + conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING; + conn->zs_out.avail_out = conn->buf_out_length; + + while (1) { + n = deflate(&conn->zs_out, Z_SYNC_FLUSH); + if (n == Z_STREAM_ERROR) { + /* + * screwed.. close the connection... we will + * get a destroy callback to take care of + * closing nicely + */ + lwsl_ext("zlib error deflate\n"); + + return -1; + } + + if (conn->zs_out.avail_out) + break; + + len_so_far = (conn->zs_out.next_out - + (conn->buf_out + + LWS_SEND_BUFFER_PRE_PADDING)); + conn->buf_out_length *= 2; + if (conn->buf_out_length > LWS_MAX_ZLIB_CONN_BUFFER) { + lwsl_ext("zlib out hit limit %u\n", + LWS_MAX_ZLIB_CONN_BUFFER); + return -1; + } + conn->buf_out = lws_realloc(conn->buf_out, + LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_out) { + lwsl_err("Out of memory\n"); + return -1; + } + lwsl_debug( + "deflate-frame ext TX did realloc to %ld\n", + conn->buf_in_length); + + conn->zs_out.next_out = (conn->buf_out + + LWS_SEND_BUFFER_PRE_PADDING + len_so_far); + conn->zs_out.avail_out = + (conn->buf_out_length - len_so_far); + } + + conn->compressed_out = 1; + + /* rewrite the buffer pointers and length */ + eff_buf->token = (char *)(conn->buf_out + + LWS_SEND_BUFFER_PRE_PADDING); + eff_buf->token_len = (int)(conn->zs_out.next_out - + (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4; + + return 0; + + case LWS_EXT_CALLBACK_PACKET_TX_PRESEND: + if (conn->compressed_out) { + conn->compressed_out = 0; + *((unsigned char *)eff_buf->token) |= 0x40; + } + break; + + case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION: + /* Avoid x-webkit-deflate-frame extension on client */ + if (!strcmp((char *)in, "x-webkit-deflate-frame")) + return 1; + break; + + default: + break; + } + + return 0; +} + diff --git a/src/engine/external/libwebsockets/extension-deflate-frame.h b/src/engine/external/libwebsockets/extension-deflate-frame.h new file mode 100644 index 00000000..00a4447a --- /dev/null +++ b/src/engine/external/libwebsockets/extension-deflate-frame.h @@ -0,0 +1,25 @@ + +#include <zlib.h> + +#define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1 +#define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION + +struct lws_ext_deflate_frame_conn { + z_stream zs_in; + z_stream zs_out; + size_t buf_pre_used; + size_t buf_pre_length; + size_t buf_in_length; + size_t buf_out_length; + int compressed_out; + unsigned char *buf_pre; + unsigned char *buf_in; + unsigned char *buf_out; +}; + +extern int lws_extension_callback_deflate_frame( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); diff --git a/src/engine/external/libwebsockets/extension-deflate-stream.c b/src/engine/external/libwebsockets/extension-deflate-stream.c new file mode 100644 index 00000000..addaa2c7 --- /dev/null +++ b/src/engine/external/libwebsockets/extension-deflate-stream.c @@ -0,0 +1,166 @@ +#include "private-libwebsockets.h" +#include "extension-deflate-stream.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define LWS_ZLIB_WINDOW_BITS 15 +#define LWS_ZLIB_MEMLEVEL 8 + +int lws_extension_callback_deflate_stream( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct lws_ext_deflate_stream_conn *conn = + (struct lws_ext_deflate_stream_conn *)user; + int n; + struct lws_tokens *eff_buf = (struct lws_tokens *)in; + + switch (reason) { + + /* + * for deflate-stream, both client and server sides act the same + */ + + case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: + case LWS_EXT_CALLBACK_CONSTRUCT: + conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL; + conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL; + conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL; + n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS); + if (n != Z_OK) { + lwsl_err("deflateInit returned %d\n", n); + return 1; + } + n = deflateInit2(&conn->zs_out, + DEFLATE_STREAM_COMPRESSION_LEVEL, Z_DEFLATED, + -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (n != Z_OK) { + lwsl_err("deflateInit returned %d\n", n); + return 1; + } + lwsl_ext("zlibs constructed\n"); + conn->remaining_in = 0; + break; + + case LWS_EXT_CALLBACK_DESTROY: + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + lwsl_ext("zlibs destructed\n"); + break; + + case LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: + + /* + * inflate the incoming compressed data + * Notice, length may be 0 and pointer NULL + * in the case we are flushing with nothing new coming in + */ + if (conn->remaining_in) { + conn->zs_in.next_in = conn->buf_in; + conn->zs_in.avail_in = conn->remaining_in; + conn->remaining_in = 0; + } else { + conn->zs_in.next_in = (unsigned char *)eff_buf->token; + conn->zs_in.avail_in = eff_buf->token_len; + } + + conn->zs_in.next_out = conn->buf_out; + conn->zs_in.avail_out = sizeof(conn->buf_out); + + n = inflate(&conn->zs_in, Z_SYNC_FLUSH); + switch (n) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + /* + * screwed.. close the connection... we will get a + * destroy callback to take care of closing nicely + */ + lwsl_err("zlib error inflate %d\n", n); + return -1; + } + + /* rewrite the buffer pointers and length */ + + eff_buf->token = (char *)conn->buf_out; + eff_buf->token_len = + sizeof(conn->buf_out) - conn->zs_in.avail_out; + + /* copy avail data if not consumed */ + if (conn->zs_in.avail_in > 0) { + conn->remaining_in = conn->zs_in.avail_in; + memcpy(conn->buf_in, conn->zs_in.next_in, + conn->zs_in.avail_in); + return 1; + } + + /* + * if we filled the output buffer, signal that we likely have + * more and need to be called again + */ + + if (eff_buf->token_len == sizeof(conn->buf_out)) + return 1; + + /* we don't need calling again until new input data comes */ + + return 0; + + case LWS_EXT_CALLBACK_FLUSH_PENDING_TX: + case LWS_EXT_CALLBACK_PACKET_TX_PRESEND: + + /* + * deflate the outgoing compressed data + */ + + conn->zs_out.next_in = (unsigned char *)eff_buf->token; + conn->zs_out.avail_in = eff_buf->token_len; + + conn->zs_out.next_out = conn->buf_out; + conn->zs_out.avail_out = sizeof(conn->buf_out); + + n = Z_PARTIAL_FLUSH; + if (reason == LWS_EXT_CALLBACK_FLUSH_PENDING_TX) + n = Z_FULL_FLUSH; + + n = deflate(&conn->zs_out, n); + if (n == Z_STREAM_ERROR) { + /* + * screwed.. close the connection... we will get a + * destroy callback to take care of closing nicely + */ + lwsl_ext("zlib error deflate\n"); + + return -1; + } + + /* rewrite the buffer pointers and length */ + + eff_buf->token = (char *)conn->buf_out; + eff_buf->token_len = + sizeof(conn->buf_out) - conn->zs_out.avail_out; + + /* + * if we filled the output buffer, signal that we likely have + * more and need to be called again... even in deflate case + * we might sometimes need to spill more than came in + */ + + if (eff_buf->token_len == sizeof(conn->buf_out)) + return 1; + + /* we don't need calling again until new input data comes */ + + return 0; + + default: + break; + } + + return 0; +} diff --git a/src/engine/external/libwebsockets/extension-deflate-stream.h b/src/engine/external/libwebsockets/extension-deflate-stream.h new file mode 100644 index 00000000..fcadc07a --- /dev/null +++ b/src/engine/external/libwebsockets/extension-deflate-stream.h @@ -0,0 +1,20 @@ + +#include <zlib.h> + +#define DEFLATE_STREAM_CHUNK 128 +#define DEFLATE_STREAM_COMPRESSION_LEVEL 1 + +struct lws_ext_deflate_stream_conn { + z_stream zs_in; + z_stream zs_out; + int remaining_in; + unsigned char buf_in[LWS_MAX_SOCKET_IO_BUF]; + unsigned char buf_out[LWS_MAX_SOCKET_IO_BUF]; +}; + +extern int lws_extension_callback_deflate_stream( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); diff --git a/src/engine/external/libwebsockets/extension.c b/src/engine/external/libwebsockets/extension.c new file mode 100644 index 00000000..b7a5792b --- /dev/null +++ b/src/engine/external/libwebsockets/extension.c @@ -0,0 +1,208 @@ +#include "private-libwebsockets.h" + +#include "extension-deflate-frame.h" +#include "extension-deflate-stream.h" + +struct libwebsocket_extension libwebsocket_internal_extensions[] = { +#ifdef LWS_EXT_DEFLATE_STREAM + { + "deflate-stream", + lws_extension_callback_deflate_stream, + sizeof(struct lws_ext_deflate_stream_conn) + }, +#else + { + "x-webkit-deflate-frame", + lws_extension_callback_deflate_frame, + sizeof(struct lws_ext_deflate_frame_conn) + }, + { + "deflate-frame", + lws_extension_callback_deflate_frame, + sizeof(struct lws_ext_deflate_frame_conn) + }, +#endif + { /* terminator */ + NULL, NULL, 0 + } +}; + +LWS_VISIBLE void +lws_context_init_extensions(struct lws_context_creation_info *info, + struct libwebsocket_context *context) +{ + context->extensions = info->extensions; + lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE); +} + +LWS_VISIBLE struct libwebsocket_extension *libwebsocket_get_internal_extensions() +{ + return libwebsocket_internal_extensions; +} + + +/* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */ + +int lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason, + void *arg, int len) +{ + int n, m, handled = 0; + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + reason, + wsi->active_extensions_user[n], + arg, len); + if (m < 0) { + lwsl_ext( + "Extension '%s' failed to handle callback %d!\n", + wsi->active_extensions[n]->name, reason); + return -1; + } + if (m > handled) + handled = m; + } + + return handled; +} + +int lws_ext_callback_for_each_extension_type( + struct libwebsocket_context *context, struct libwebsocket *wsi, + int reason, void *arg, int len) +{ + int n = 0, m, handled = 0; + struct libwebsocket_extension *ext = context->extensions; + + while (ext && ext->callback && !handled) { + m = ext->callback(context, ext, wsi, reason, + (void *)(long)n, arg, len); + if (m < 0) { + lwsl_ext( + "Extension '%s' failed to handle callback %d!\n", + wsi->active_extensions[n]->name, reason); + return -1; + } + if (m) + handled = 1; + + ext++; + n++; + } + + return 0; +} + +int +lws_issue_raw_ext_access(struct libwebsocket *wsi, + unsigned char *buf, size_t len) +{ + int ret; + struct lws_tokens eff_buf; + int m; + int n = 0; + + eff_buf.token = (char *)buf; + eff_buf.token_len = len; + + /* + * while we have original buf to spill ourselves, or extensions report + * more in their pipeline + */ + + ret = 1; + while (ret == 1) { + + /* default to nobody has more to spill */ + + ret = 0; + + /* show every extension the new incoming data */ + m = lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, &eff_buf, 0); + if (m < 0) + return -1; + if (m) /* handled */ + ret = 1; + + if ((char *)buf != eff_buf.token) + /* + * extension recreated it: + * need to buffer this if not all sent + */ + wsi->u.ws.clean_buffer = 0; + + /* assuming they left us something to send, send it */ + + if (eff_buf.token_len) { + n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len); + if (n < 0) { + lwsl_info("closing from ext access\n"); + return -1; + } + + /* always either sent it all or privately buffered */ + if (wsi->u.ws.clean_buffer) + len = n; + } + + lwsl_parser("written %d bytes to client\n", n); + + /* no extension has more to spill? Then we can go */ + + if (!ret) + break; + + /* we used up what we had */ + + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* + * Did that leave the pipe choked? + * Or we had to hold on to some of it? + */ + + if (!lws_send_pipe_choked(wsi) && !wsi->truncated_send_len) + /* no we could add more, lets's do that */ + continue; + + lwsl_debug("choked\n"); + + /* + * Yes, he's choked. Don't spill the rest now get a callback + * when he is ready to send and take care of it there + */ + libwebsocket_callback_on_writable( + wsi->protocol->owning_server, wsi); + wsi->extension_data_pending = 1; + ret = 0; + } + + return len; +} + +int +lws_any_extension_handled(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons r, + void *v, size_t len) +{ + int n; + int handled = 0; + + /* maybe an extension will take care of it for us */ + + for (n = 0; n < wsi->count_active_extensions && !handled; n++) { + if (!wsi->active_extensions[n]->callback) + continue; + + handled |= wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + r, wsi->active_extensions_user[n], v, len); + } + + return handled; +} diff --git a/src/engine/external/libwebsockets/getifaddrs.h b/src/engine/external/libwebsockets/getifaddrs.h new file mode 100644 index 00000000..da69b50e --- /dev/null +++ b/src/engine/external/libwebsockets/getifaddrs.h @@ -0,0 +1,76 @@ +#if HAVE_GETIFADDRS +#include <sys/types.h> +#include <ifaddrs.h> +#else +#ifdef __cplusplus +extern "C" { +#endif +/* + * Copyright (c) 2000 Kungliga Tekniska H�gskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */ + +#ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791 +#define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791 + +/* + * the interface is defined in terms of the fields below, and this is + * sometimes #define'd, so there seems to be no simple way of solving + * this and this seemed the best. */ + +#undef ifa_dstaddr + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr +#endif + +int getifaddrs(struct ifaddrs **); + +void freeifaddrs(struct ifaddrs *); + +#endif /* __ifaddrs_h__ */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/engine/external/libwebsockets/handshake.c b/src/engine/external/libwebsockets/handshake.c new file mode 100644 index 00000000..856297db --- /dev/null +++ b/src/engine/external/libwebsockets/handshake.c @@ -0,0 +1,232 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +/* + * -04 of the protocol (actually the 80th version) has a radically different + * handshake. The 04 spec gives the following idea + * + * The handshake from the client looks as follows: + * + * GET /chat HTTP/1.1 + * Host: server.example.com + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== + * Sec-WebSocket-Origin: http://example.com + * Sec-WebSocket-Protocol: chat, superchat + * Sec-WebSocket-Version: 4 + * + * The handshake from the server looks as follows: + * + * HTTP/1.1 101 Switching Protocols + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= + * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== + * Sec-WebSocket-Protocol: chat + */ + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif +/* + * We have to take care about parsing because the headers may be split + * into multiple fragments. They may contain unknown headers with arbitrary + * argument lengths. So, we parse using a single-character at a time state + * machine that is completely independent of packet size. + */ + +LWS_VISIBLE int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char *buf, size_t len) +{ + size_t n; + int body_chunk_len; + unsigned char *last_char; + + switch (wsi->state) { +#ifdef LWS_USE_HTTP2 + case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE: + case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS: + case WSI_STATE_HTTP2_ESTABLISHED: + n = 0; + while (n < len) { + /* + * we were accepting input but now we stopped doing so + */ + if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { + lws_rxflow_cache(wsi, buf, n, len); + + return 1; + } + + /* account for what we're using in rxflow buffer */ + if (wsi->rxflow_buffer) + wsi->rxflow_pos++; + if (lws_http2_parser(context, wsi, buf[n++])) + goto bail; + } + break; +#endif +http_new: + case WSI_STATE_HTTP: + wsi->hdr_parsing_completed = 0; + /* fallthru */ + case WSI_STATE_HTTP_ISSUING_FILE: + wsi->state = WSI_STATE_HTTP_HEADERS; + wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; + wsi->u.hdr.lextable_pos = 0; + /* fallthru */ + case WSI_STATE_HTTP_HEADERS: + lwsl_parser("issuing %d bytes to parser\n", (int)len); + + if (lws_handshake_client(wsi, &buf, len)) + goto bail; + + last_char = buf; + if (lws_handshake_server(context, wsi, &buf, len)) + /* Handshake indicates this session is done. */ + goto bail; + + /* It's possible that we've exhausted our data already, but + * lws_handshake_server doesn't update len for us. Figure out how + * much was read, so that we can proceed appropriately: */ + len -= (buf - last_char); + + if (!wsi->hdr_parsing_completed) + /* More header content on the way */ + goto read_ok; + + switch (wsi->state) { + case WSI_STATE_HTTP: + case WSI_STATE_HTTP_HEADERS: + goto http_complete; + case WSI_STATE_HTTP_ISSUING_FILE: + goto read_ok; + case WSI_STATE_HTTP_BODY: + wsi->u.http.content_remain = wsi->u.http.content_length; + goto http_postbody; + default: + break; + } + break; + + case WSI_STATE_HTTP_BODY: +http_postbody: + while (len && wsi->u.http.content_remain) { + /* Copy as much as possible, up to the limit of: + * what we have in the read buffer (len) + * remaining portion of the POST body (content_remain) + */ + body_chunk_len = min(wsi->u.http.content_remain,len); + wsi->u.http.content_remain -= body_chunk_len; + len -= body_chunk_len; + + if (wsi->protocol->callback) { + n = wsi->protocol->callback( + wsi->protocol->owning_server, wsi, + LWS_CALLBACK_HTTP_BODY, wsi->user_space, + buf, body_chunk_len); + if (n) + goto bail; + } + buf += body_chunk_len; + + if (!wsi->u.http.content_remain) { + /* he sent the content in time */ + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + if (wsi->protocol->callback) { + n = wsi->protocol->callback( + wsi->protocol->owning_server, wsi, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + wsi->user_space, NULL, 0); + if (n) + goto bail; + } + goto http_complete; + } else + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_HTTP_CONTENT, + AWAITING_TIMEOUT); + } + break; + + case WSI_STATE_ESTABLISHED: + case WSI_STATE_AWAITING_CLOSE_ACK: + if (lws_handshake_client(wsi, &buf, len)) + goto bail; + switch (wsi->mode) { + case LWS_CONNMODE_WS_SERVING: + + if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0) { + lwsl_info("interpret_incoming_packet has bailed\n"); + goto bail; + } + break; + } + break; + default: + lwsl_err("libwebsocket_read: Unhandled state\n"); + break; + } + +read_ok: + /* Nothing more to do for now. */ + lwsl_debug("libwebsocket_read: read_ok\n"); + + return 0; + +http_complete: + lwsl_debug("libwebsocket_read: http_complete\n"); + + /* Did the client want to keep the HTTP connection going? */ + + if (wsi->u.http.connection_type == HTTP_CONNECTION_KEEP_ALIVE) { + lwsl_debug("libwebsocket_read: keep-alive\n"); + wsi->state = WSI_STATE_HTTP; + wsi->mode = LWS_CONNMODE_HTTP_SERVING; + + /* He asked for it to stay alive indefinitely */ + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + + if (lws_allocate_header_table(wsi)) + goto bail; + + /* If we're (re)starting on headers, need other implied init */ + wsi->u.hdr.ues = URIES_IDLE; + + /* If we have more data, loop back around: */ + if (len) + goto http_new; + + return 0; + } + +bail: + lwsl_debug("closing connection at libwebsocket_read bail:\n"); + + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + + return -1; +} diff --git a/src/engine/external/libwebsockets/huftable.h b/src/engine/external/libwebsockets/huftable.h new file mode 100644 index 00000000..385a83be --- /dev/null +++ b/src/engine/external/libwebsockets/huftable.h @@ -0,0 +1,530 @@ +static unsigned char lextable[] = { +/* pos 0000: 0 */ /* 0 */ 0x42 /* (to 0x0084 state 98) */, + /* 1 */ 0x01 /* (to 0x0002 state 1) */, +/* pos 0002: 1 */ /* 0 */ 0x5C /* (to 0x00BA state 151) */, + /* 1 */ 0x01 /* (to 0x0004 state 2) */, +/* pos 0004: 2 */ /* 0 */ 0x66 /* (to 0x00D0 state 173) */, + /* 1 */ 0x01 /* (to 0x0006 state 3) */, +/* pos 0006: 3 */ /* 0 */ 0x74 /* (to 0x00EE state 204) */, + /* 1 */ 0x01 /* (to 0x0008 state 4) */, +/* pos 0008: 4 */ /* 0 */ 0x8C /* (to 0x0120 state 263) */, + /* 1 */ 0x01 /* (to 0x000A state 5) */, +/* pos 000a: 5 */ /* 0 */ 0x46 /* (to 0x0096 state 113) */, + /* 1 */ 0x01 /* (to 0x000C state 6) */, +/* pos 000c: 6 */ /* 0 */ 0x75 /* (to 0x00F6 state 211) */, + /* 1 */ 0x01 /* (to 0x000E state 7) */, +/* pos 000e: 7 */ /* 0 */ 0x40 /* (to 0x008E state 104) */, + /* 1 */ 0x01 /* (to 0x0010 state 8) */, +/* pos 0010: 8 */ /* 0 */ 0x45 /* (to 0x009A state 116) */, + /* 1 */ 0x01 /* (to 0x0012 state 9) */, +/* pos 0012: 9 */ /* 0 */ 0x40 /* (to 0x0092 state 108) */, + /* 1 */ 0x01 /* (to 0x0014 state 10) */, +/* pos 0014: 10 */ /* 0 */ 0x01 /* (to 0x0016 state 11) */, + /* 1 */ 0x03 /* (to 0x001A state 14) */, +/* pos 0016: 11 */ /* 0 */ 0x01 /* (to 0x0018 state 12) */, + /* 1 */ 0x5B /* (to 0x00CC state 166) */, +/* pos 0018: 12 */ /* terminal 0 */ 0x00, + /* terminal 36 */ 0x24, +/* pos 001a: 14 */ /* 0 */ 0x72 /* (to 0x00FE state 220) */, + /* 1 */ 0x01 /* (to 0x001C state 15) */, +/* pos 001c: 15 */ /* 0 */ 0x72 /* (to 0x0100 state 222) */, + /* 1 */ 0x01 /* (to 0x001E state 16) */, +/* pos 001e: 16 */ /* 0 */ 0x53 /* (to 0x00C4 state 158) */, + /* 1 */ 0x01 /* (to 0x0020 state 17) */, +/* pos 0020: 17 */ /* terminal 123 */ 0x7B, + /* 1 */ 0x01 /* (to 0x0022 state 18) */, +/* pos 0022: 18 */ /* 0 */ 0x6B /* (to 0x00F8 state 216) */, + /* 1 */ 0x01 /* (to 0x0024 state 19) */, +/* pos 0024: 19 */ /* 0 */ 0x84 /* (to 0x012C state 279) */, + /* 1 */ 0x01 /* (to 0x0026 state 20) */, +/* pos 0026: 20 */ /* 0 */ 0x01 /* (to 0x0028 state 21) */, + /* 1 */ 0x06 /* (to 0x0032 state 27) */, +/* pos 0028: 21 */ /* 0 */ 0xB3 /* (to 0x018E state 377) */, + /* 1 */ 0x01 /* (to 0x002A state 22) */, +/* pos 002a: 22 */ /* 0 */ 0xC3 /* (to 0x01B0 state 414) */, + /* 1 */ 0x01 /* (to 0x002C state 23) */, +/* pos 002c: 23 */ /* 0 */ 0x01 /* (to 0x002E state 24) */, + /* 1 */ 0x8C /* (to 0x0144 state 301) */, +/* pos 002e: 24 */ /* 0 */ 0x01 /* (to 0x0030 state 25) */, + /* 1 */ 0x8A /* (to 0x0142 state 298) */, +/* pos 0030: 25 */ /* terminal 1 */ 0x01, + /* terminal 135 */ 0x87, +/* pos 0032: 27 */ /* 0 */ 0x8E /* (to 0x014E state 314) */, + /* 1 */ 0x01 /* (to 0x0034 state 28) */, +/* pos 0034: 28 */ /* 0 */ 0x0F /* (to 0x0052 state 50) */, + /* 1 */ 0x01 /* (to 0x0036 state 29) */, +/* pos 0036: 29 */ /* 0 */ 0xA4 /* (to 0x017E state 362) */, + /* 1 */ 0x01 /* (to 0x0038 state 30) */, +/* pos 0038: 30 */ /* 0 */ 0xB7 /* (to 0x01A6 state 403) */, + /* 1 */ 0x01 /* (to 0x003A state 31) */, +/* pos 003a: 31 */ /* 0 */ 0xC8 /* (to 0x01CA state 440) */, + /* 1 */ 0x01 /* (to 0x003C state 32) */, +/* pos 003c: 32 */ /* 0 */ 0x01 /* (to 0x003E state 33) */, + /* 1 */ 0x0F /* (to 0x005A state 55) */, +/* pos 003e: 33 */ /* 0 */ 0x01 /* (to 0x0040 state 34) */, + /* 1 */ 0x07 /* (to 0x004C state 46) */, +/* pos 0040: 34 */ /* 0 */ 0x01 /* (to 0x0042 state 35) */, + /* 1 */ 0x03 /* (to 0x0046 state 39) */, +/* pos 0042: 35 */ /* terminal 254 */ 0xFE, + /* 1 */ 0x01 /* (to 0x0044 state 36) */, +/* pos 0044: 36 */ /* terminal 2 */ 0x02, + /* terminal 3 */ 0x03, +/* pos 0046: 39 */ /* 0 */ 0x01 /* (to 0x0048 state 40) */, + /* 1 */ 0x02 /* (to 0x004A state 43) */, +/* pos 0048: 40 */ /* terminal 4 */ 0x04, + /* terminal 5 */ 0x05, +/* pos 004a: 43 */ /* terminal 6 */ 0x06, + /* terminal 7 */ 0x07, +/* pos 004c: 46 */ /* 0 */ 0x01 /* (to 0x004E state 47) */, + /* 1 */ 0x0E /* (to 0x0068 state 67) */, +/* pos 004e: 47 */ /* 0 */ 0x01 /* (to 0x0050 state 48) */, + /* 1 */ 0x0C /* (to 0x0066 state 63) */, +/* pos 0050: 48 */ /* terminal 8 */ 0x08, + /* terminal 11 */ 0x0B, +/* pos 0052: 50 */ /* 0 */ 0xA7 /* (to 0x01A0 state 396) */, + /* 1 */ 0x01 /* (to 0x0054 state 51) */, +/* pos 0054: 51 */ /* 0 */ 0x01 /* (to 0x0056 state 52) */, + /* 1 */ 0x7B /* (to 0x014A state 309) */, +/* pos 0056: 52 */ /* terminal 239 */ 0xEF, + /* 1 */ 0x01 /* (to 0x0058 state 53) */, +/* pos 0058: 53 */ /* terminal 9 */ 0x09, + /* terminal 142 */ 0x8E, +/* pos 005a: 55 */ /* 0 */ 0x0A /* (to 0x006E state 74) */, + /* 1 */ 0x01 /* (to 0x005C state 56) */, +/* pos 005c: 56 */ /* 0 */ 0x11 /* (to 0x007E state 91) */, + /* 1 */ 0x01 /* (to 0x005E state 57) */, +/* pos 005e: 57 */ /* 0 */ 0x64 /* (to 0x0126 state 274) */, + /* 1 */ 0x01 /* (to 0x0060 state 58) */, +/* pos 0060: 58 */ /* terminal 249 */ 0xF9, + /* 1 */ 0x01 /* (to 0x0062 state 59) */, +/* pos 0062: 59 */ /* 0 */ 0x01 /* (to 0x0064 state 60) */, + /* 1 */ 0x0A /* (to 0x0076 state 81) */, +/* pos 0064: 60 */ /* terminal 10 */ 0x0A, + /* terminal 13 */ 0x0D, +/* pos 0066: 63 */ /* terminal 12 */ 0x0C, + /* terminal 14 */ 0x0E, +/* pos 0068: 67 */ /* 0 */ 0x01 /* (to 0x006A state 68) */, + /* 1 */ 0x02 /* (to 0x006C state 71) */, +/* pos 006a: 68 */ /* terminal 15 */ 0x0F, + /* terminal 16 */ 0x10, +/* pos 006c: 71 */ /* terminal 17 */ 0x11, + /* terminal 18 */ 0x12, +/* pos 006e: 74 */ /* 0 */ 0x01 /* (to 0x0070 state 75) */, + /* 1 */ 0x05 /* (to 0x0078 state 84) */, +/* pos 0070: 75 */ /* 0 */ 0x01 /* (to 0x0072 state 76) */, + /* 1 */ 0x02 /* (to 0x0074 state 79) */, +/* pos 0072: 76 */ /* terminal 19 */ 0x13, + /* terminal 20 */ 0x14, +/* pos 0074: 79 */ /* terminal 21 */ 0x15, + /* terminal 23 */ 0x17, +/* pos 0076: 81 */ /* terminal 22 */ 0x16, + /* terminal 256 */ 0x00, +/* pos 0078: 84 */ /* 0 */ 0x01 /* (to 0x007A state 85) */, + /* 1 */ 0x02 /* (to 0x007C state 88) */, +/* pos 007a: 85 */ /* terminal 24 */ 0x18, + /* terminal 25 */ 0x19, +/* pos 007c: 88 */ /* terminal 26 */ 0x1A, + /* terminal 27 */ 0x1B, +/* pos 007e: 91 */ /* 0 */ 0x01 /* (to 0x0080 state 92) */, + /* 1 */ 0x02 /* (to 0x0082 state 95) */, +/* pos 0080: 92 */ /* terminal 28 */ 0x1C, + /* terminal 29 */ 0x1D, +/* pos 0082: 95 */ /* terminal 30 */ 0x1E, + /* terminal 31 */ 0x1F, +/* pos 0084: 98 */ /* 0 */ 0x13 /* (to 0x00AA state 133) */, + /* 1 */ 0x01 /* (to 0x0086 state 99) */, +/* pos 0086: 99 */ /* 0 */ 0x01 /* (to 0x0088 state 100) */, + /* 1 */ 0x0F /* (to 0x00A4 state 129) */, +/* pos 0088: 100 */ /* 0 */ 0x4B /* (to 0x011E state 258) */, + /* 1 */ 0x01 /* (to 0x008A state 101) */, +/* pos 008a: 101 */ /* 0 */ 0x01 /* (to 0x008C state 102) */, + /* 1 */ 0x0C /* (to 0x00A2 state 126) */, +/* pos 008c: 102 */ /* terminal 32 */ 0x20, + /* terminal 37 */ 0x25, +/* pos 008e: 104 */ /* 0 */ 0x01 /* (to 0x0090 state 105) */, + /* 1 */ 0x08 /* (to 0x009E state 119) */, +/* pos 0090: 105 */ /* terminal 33 */ 0x21, + /* terminal 34 */ 0x22, +/* pos 0092: 108 */ /* terminal 124 */ 0x7C, + /* 1 */ 0x01 /* (to 0x0094 state 109) */, +/* pos 0094: 109 */ /* terminal 35 */ 0x23, + /* terminal 62 */ 0x3E, +/* pos 0096: 113 */ /* 0 */ 0x01 /* (to 0x0098 state 114) */, + /* 1 */ 0x05 /* (to 0x00A0 state 124) */, +/* pos 0098: 114 */ /* terminal 38 */ 0x26, + /* terminal 42 */ 0x2A, +/* pos 009a: 116 */ /* terminal 63 */ 0x3F, + /* 1 */ 0x01 /* (to 0x009C state 117) */, +/* pos 009c: 117 */ /* terminal 39 */ 0x27, + /* terminal 43 */ 0x2B, +/* pos 009e: 119 */ /* terminal 40 */ 0x28, + /* terminal 41 */ 0x29, +/* pos 00a0: 124 */ /* terminal 44 */ 0x2C, + /* terminal 59 */ 0x3B, +/* pos 00a2: 126 */ /* terminal 45 */ 0x2D, + /* terminal 46 */ 0x2E, +/* pos 00a4: 129 */ /* 0 */ 0x01 /* (to 0x00A6 state 130) */, + /* 1 */ 0x08 /* (to 0x00B4 state 144) */, +/* pos 00a6: 130 */ /* 0 */ 0x01 /* (to 0x00A8 state 131) */, + /* 1 */ 0x06 /* (to 0x00B2 state 141) */, +/* pos 00a8: 131 */ /* terminal 47 */ 0x2F, + /* terminal 51 */ 0x33, +/* pos 00aa: 133 */ /* 0 */ 0x01 /* (to 0x00AC state 134) */, + /* 1 */ 0x2D /* (to 0x0104 state 229) */, +/* pos 00ac: 134 */ /* 0 */ 0x01 /* (to 0x00AE state 135) */, + /* 1 */ 0x02 /* (to 0x00B0 state 138) */, +/* pos 00ae: 135 */ /* terminal 48 */ 0x30, + /* terminal 49 */ 0x31, +/* pos 00b0: 138 */ /* terminal 50 */ 0x32, + /* terminal 97 */ 0x61, +/* pos 00b2: 141 */ /* terminal 52 */ 0x34, + /* terminal 53 */ 0x35, +/* pos 00b4: 144 */ /* 0 */ 0x01 /* (to 0x00B6 state 145) */, + /* 1 */ 0x02 /* (to 0x00B8 state 148) */, +/* pos 00b6: 145 */ /* terminal 54 */ 0x36, + /* terminal 55 */ 0x37, +/* pos 00b8: 148 */ /* terminal 56 */ 0x38, + /* terminal 57 */ 0x39, +/* pos 00ba: 151 */ /* 0 */ 0x06 /* (to 0x00C6 state 160) */, + /* 1 */ 0x01 /* (to 0x00BC state 152) */, +/* pos 00bc: 152 */ /* 0 */ 0x2C /* (to 0x0114 state 246) */, + /* 1 */ 0x01 /* (to 0x00BE state 153) */, +/* pos 00be: 153 */ /* 0 */ 0x2F /* (to 0x011C state 256) */, + /* 1 */ 0x01 /* (to 0x00C0 state 154) */, +/* pos 00c0: 154 */ /* 0 */ 0x01 /* (to 0x00C2 state 155) */, + /* 1 */ 0x07 /* (to 0x00CE state 170) */, +/* pos 00c2: 155 */ /* terminal 58 */ 0x3A, + /* terminal 66 */ 0x42, +/* pos 00c4: 158 */ /* terminal 60 */ 0x3C, + /* terminal 96 */ 0x60, +/* pos 00c6: 160 */ /* 0 */ 0x01 /* (to 0x00C8 state 161) */, + /* 1 */ 0x21 /* (to 0x0108 state 232) */, +/* pos 00c8: 161 */ /* 0 */ 0x01 /* (to 0x00CA state 162) */, + /* 1 */ 0x1D /* (to 0x0102 state 224) */, +/* pos 00ca: 162 */ /* terminal 61 */ 0x3D, + /* terminal 65 */ 0x41, +/* pos 00cc: 166 */ /* terminal 64 */ 0x40, + /* terminal 91 */ 0x5B, +/* pos 00ce: 170 */ /* terminal 67 */ 0x43, + /* terminal 68 */ 0x44, +/* pos 00d0: 173 */ /* 0 */ 0x01 /* (to 0x00D2 state 174) */, + /* 1 */ 0x08 /* (to 0x00E0 state 189) */, +/* pos 00d2: 174 */ /* 0 */ 0x01 /* (to 0x00D4 state 175) */, + /* 1 */ 0x04 /* (to 0x00DA state 182) */, +/* pos 00d4: 175 */ /* 0 */ 0x01 /* (to 0x00D6 state 176) */, + /* 1 */ 0x02 /* (to 0x00D8 state 179) */, +/* pos 00d6: 176 */ /* terminal 69 */ 0x45, + /* terminal 70 */ 0x46, +/* pos 00d8: 179 */ /* terminal 71 */ 0x47, + /* terminal 72 */ 0x48, +/* pos 00da: 182 */ /* 0 */ 0x01 /* (to 0x00DC state 183) */, + /* 1 */ 0x02 /* (to 0x00DE state 186) */, +/* pos 00dc: 183 */ /* terminal 73 */ 0x49, + /* terminal 74 */ 0x4A, +/* pos 00de: 186 */ /* terminal 75 */ 0x4B, + /* terminal 76 */ 0x4C, +/* pos 00e0: 189 */ /* 0 */ 0x01 /* (to 0x00E2 state 190) */, + /* 1 */ 0x04 /* (to 0x00E8 state 197) */, +/* pos 00e2: 190 */ /* 0 */ 0x01 /* (to 0x00E4 state 191) */, + /* 1 */ 0x02 /* (to 0x00E6 state 194) */, +/* pos 00e4: 191 */ /* terminal 77 */ 0x4D, + /* terminal 78 */ 0x4E, +/* pos 00e6: 194 */ /* terminal 79 */ 0x4F, + /* terminal 80 */ 0x50, +/* pos 00e8: 197 */ /* 0 */ 0x01 /* (to 0x00EA state 198) */, + /* 1 */ 0x02 /* (to 0x00EC state 201) */, +/* pos 00ea: 198 */ /* terminal 81 */ 0x51, + /* terminal 82 */ 0x52, +/* pos 00ec: 201 */ /* terminal 83 */ 0x53, + /* terminal 84 */ 0x54, +/* pos 00ee: 204 */ /* 0 */ 0x01 /* (to 0x00F0 state 205) */, + /* 1 */ 0x11 /* (to 0x0110 state 242) */, +/* pos 00f0: 205 */ /* 0 */ 0x01 /* (to 0x00F2 state 206) */, + /* 1 */ 0x02 /* (to 0x00F4 state 209) */, +/* pos 00f2: 206 */ /* terminal 85 */ 0x55, + /* terminal 86 */ 0x56, +/* pos 00f4: 209 */ /* terminal 87 */ 0x57, + /* terminal 89 */ 0x59, +/* pos 00f6: 211 */ /* terminal 88 */ 0x58, + /* terminal 90 */ 0x5A, +/* pos 00f8: 216 */ /* 0 */ 0x01 /* (to 0x00FA state 217) */, + /* 1 */ 0x1F /* (to 0x0136 state 286) */, +/* pos 00fa: 217 */ /* 0 */ 0x01 /* (to 0x00FC state 218) */, + /* 1 */ 0x17 /* (to 0x0128 state 276) */, +/* pos 00fc: 218 */ /* terminal 92 */ 0x5C, + /* terminal 195 */ 0xC3, +/* pos 00fe: 220 */ /* terminal 93 */ 0x5D, + /* terminal 126 */ 0x7E, +/* pos 0100: 222 */ /* terminal 94 */ 0x5E, + /* terminal 125 */ 0x7D, +/* pos 0102: 224 */ /* terminal 95 */ 0x5F, + /* terminal 98 */ 0x62, +/* pos 0104: 229 */ /* 0 */ 0x01 /* (to 0x0106 state 230) */, + /* 1 */ 0x05 /* (to 0x010E state 240) */, +/* pos 0106: 230 */ /* terminal 99 */ 0x63, + /* terminal 101 */ 0x65, +/* pos 0108: 232 */ /* 0 */ 0x01 /* (to 0x010A state 233) */, + /* 1 */ 0x02 /* (to 0x010C state 237) */, +/* pos 010a: 233 */ /* terminal 100 */ 0x64, + /* terminal 102 */ 0x66, +/* pos 010c: 237 */ /* terminal 103 */ 0x67, + /* terminal 104 */ 0x68, +/* pos 010e: 240 */ /* terminal 105 */ 0x69, + /* terminal 111 */ 0x6F, +/* pos 0110: 242 */ /* 0 */ 0x01 /* (to 0x0112 state 243) */, + /* 1 */ 0x05 /* (to 0x011A state 254) */, +/* pos 0112: 243 */ /* terminal 106 */ 0x6A, + /* terminal 107 */ 0x6B, +/* pos 0114: 246 */ /* 0 */ 0x01 /* (to 0x0116 state 247) */, + /* 1 */ 0x02 /* (to 0x0118 state 250) */, +/* pos 0116: 247 */ /* terminal 108 */ 0x6C, + /* terminal 109 */ 0x6D, +/* pos 0118: 250 */ /* terminal 110 */ 0x6E, + /* terminal 112 */ 0x70, +/* pos 011a: 254 */ /* terminal 113 */ 0x71, + /* terminal 118 */ 0x76, +/* pos 011c: 256 */ /* terminal 114 */ 0x72, + /* terminal 117 */ 0x75, +/* pos 011e: 258 */ /* terminal 115 */ 0x73, + /* terminal 116 */ 0x74, +/* pos 0120: 263 */ /* 0 */ 0x01 /* (to 0x0122 state 264) */, + /* 1 */ 0x02 /* (to 0x0124 state 267) */, +/* pos 0122: 264 */ /* terminal 119 */ 0x77, + /* terminal 120 */ 0x78, +/* pos 0124: 267 */ /* terminal 121 */ 0x79, + /* terminal 122 */ 0x7A, +/* pos 0126: 274 */ /* terminal 127 */ 0x7F, + /* terminal 220 */ 0xDC, +/* pos 0128: 276 */ /* terminal 208 */ 0xD0, + /* 1 */ 0x01 /* (to 0x012A state 277) */, +/* pos 012a: 277 */ /* terminal 128 */ 0x80, + /* terminal 130 */ 0x82, +/* pos 012c: 279 */ /* 0 */ 0x2E /* (to 0x0188 state 372) */, + /* 1 */ 0x01 /* (to 0x012E state 280) */, +/* pos 012e: 280 */ /* 0 */ 0x01 /* (to 0x0130 state 281) */, + /* 1 */ 0x1B /* (to 0x0164 state 332) */, +/* pos 0130: 281 */ /* 0 */ 0x01 /* (to 0x0132 state 282) */, + /* 1 */ 0x06 /* (to 0x013C state 291) */, +/* pos 0132: 282 */ /* terminal 230 */ 0xE6, + /* 1 */ 0x01 /* (to 0x0134 state 283) */, +/* pos 0134: 283 */ /* terminal 129 */ 0x81, + /* terminal 132 */ 0x84, +/* pos 0136: 286 */ /* 0 */ 0x01 /* (to 0x0138 state 287) */, + /* 1 */ 0x14 /* (to 0x015E state 328) */, +/* pos 0138: 287 */ /* 0 */ 0x01 /* (to 0x013A state 288) */, + /* 1 */ 0x30 /* (to 0x0198 state 388) */, +/* pos 013a: 288 */ /* terminal 131 */ 0x83, + /* terminal 162 */ 0xA2, +/* pos 013c: 291 */ /* 0 */ 0x01 /* (to 0x013E state 292) */, + /* 1 */ 0x02 /* (to 0x0140 state 296) */, +/* pos 013e: 292 */ /* terminal 133 */ 0x85, + /* terminal 134 */ 0x86, +/* pos 0140: 296 */ /* terminal 136 */ 0x88, + /* terminal 146 */ 0x92, +/* pos 0142: 298 */ /* terminal 137 */ 0x89, + /* terminal 138 */ 0x8A, +/* pos 0144: 301 */ /* 0 */ 0x01 /* (to 0x0146 state 302) */, + /* 1 */ 0x02 /* (to 0x0148 state 305) */, +/* pos 0146: 302 */ /* terminal 139 */ 0x8B, + /* terminal 140 */ 0x8C, +/* pos 0148: 305 */ /* terminal 141 */ 0x8D, + /* terminal 143 */ 0x8F, +/* pos 014a: 309 */ /* 0 */ 0x01 /* (to 0x014C state 310) */, + /* 1 */ 0x06 /* (to 0x0156 state 319) */, +/* pos 014c: 310 */ /* terminal 144 */ 0x90, + /* terminal 145 */ 0x91, +/* pos 014e: 314 */ /* 0 */ 0x01 /* (to 0x0150 state 315) */, + /* 1 */ 0x12 /* (to 0x0172 state 350) */, +/* pos 0150: 315 */ /* 0 */ 0x01 /* (to 0x0152 state 316) */, + /* 1 */ 0x05 /* (to 0x015A state 325) */, +/* pos 0152: 316 */ /* 0 */ 0x01 /* (to 0x0154 state 317) */, + /* 1 */ 0x03 /* (to 0x0158 state 322) */, +/* pos 0154: 317 */ /* terminal 147 */ 0x93, + /* terminal 149 */ 0x95, +/* pos 0156: 319 */ /* terminal 148 */ 0x94, + /* terminal 159 */ 0x9F, +/* pos 0158: 322 */ /* terminal 150 */ 0x96, + /* terminal 151 */ 0x97, +/* pos 015a: 325 */ /* 0 */ 0x01 /* (to 0x015C state 326) */, + /* 1 */ 0x08 /* (to 0x016A state 338) */, +/* pos 015c: 326 */ /* terminal 152 */ 0x98, + /* terminal 155 */ 0x9B, +/* pos 015e: 328 */ /* 0 */ 0x42 /* (to 0x01E2 state 465) */, + /* 1 */ 0x01 /* (to 0x0160 state 329) */, +/* pos 0160: 329 */ /* 0 */ 0x01 /* (to 0x0162 state 330) */, + /* 1 */ 0x0C /* (to 0x0178 state 355) */, +/* pos 0162: 330 */ /* terminal 153 */ 0x99, + /* terminal 161 */ 0xA1, +/* pos 0164: 332 */ /* 0 */ 0x01 /* (to 0x0166 state 333) */, + /* 1 */ 0x05 /* (to 0x016E state 347) */, +/* pos 0166: 333 */ /* 0 */ 0x01 /* (to 0x0168 state 334) */, + /* 1 */ 0x03 /* (to 0x016C state 342) */, +/* pos 0168: 334 */ /* terminal 154 */ 0x9A, + /* terminal 156 */ 0x9C, +/* pos 016a: 338 */ /* terminal 157 */ 0x9D, + /* terminal 158 */ 0x9E, +/* pos 016c: 342 */ /* terminal 160 */ 0xA0, + /* terminal 163 */ 0xA3, +/* pos 016e: 347 */ /* 0 */ 0x01 /* (to 0x0170 state 348) */, + /* 1 */ 0x07 /* (to 0x017C state 360) */, +/* pos 0170: 348 */ /* terminal 164 */ 0xA4, + /* terminal 169 */ 0xA9, +/* pos 0172: 350 */ /* 0 */ 0x01 /* (to 0x0174 state 351) */, + /* 1 */ 0x09 /* (to 0x0184 state 369) */, +/* pos 0174: 351 */ /* 0 */ 0x01 /* (to 0x0176 state 352) */, + /* 1 */ 0x03 /* (to 0x017A state 357) */, +/* pos 0176: 352 */ /* terminal 165 */ 0xA5, + /* terminal 166 */ 0xA6, +/* pos 0178: 355 */ /* terminal 167 */ 0xA7, + /* terminal 172 */ 0xAC, +/* pos 017a: 357 */ /* terminal 168 */ 0xA8, + /* terminal 174 */ 0xAE, +/* pos 017c: 360 */ /* terminal 170 */ 0xAA, + /* terminal 173 */ 0xAD, +/* pos 017e: 362 */ /* 0 */ 0x01 /* (to 0x0180 state 363) */, + /* 1 */ 0x1B /* (to 0x01B4 state 417) */, +/* pos 0180: 363 */ /* 0 */ 0x01 /* (to 0x0182 state 364) */, + /* 1 */ 0x2A /* (to 0x01D4 state 449) */, +/* pos 0182: 364 */ /* terminal 171 */ 0xAB, + /* terminal 206 */ 0xCE, +/* pos 0184: 369 */ /* 0 */ 0x01 /* (to 0x0186 state 370) */, + /* 1 */ 0x09 /* (to 0x0196 state 385) */, +/* pos 0186: 370 */ /* terminal 175 */ 0xAF, + /* terminal 180 */ 0xB4, +/* pos 0188: 372 */ /* 0 */ 0x01 /* (to 0x018A state 373) */, + /* 1 */ 0x27 /* (to 0x01D6 state 451) */, +/* pos 018a: 373 */ /* 0 */ 0x01 /* (to 0x018C state 374) */, + /* 1 */ 0x05 /* (to 0x0194 state 381) */, +/* pos 018c: 374 */ /* terminal 176 */ 0xB0, + /* terminal 177 */ 0xB1, +/* pos 018e: 377 */ /* 0 */ 0x01 /* (to 0x0190 state 378) */, + /* 1 */ 0x07 /* (to 0x019C state 393) */, +/* pos 0190: 378 */ /* 0 */ 0x01 /* (to 0x0192 state 379) */, + /* 1 */ 0x05 /* (to 0x019A state 390) */, +/* pos 0192: 379 */ /* terminal 178 */ 0xB2, + /* terminal 181 */ 0xB5, +/* pos 0194: 381 */ /* terminal 179 */ 0xB3, + /* terminal 209 */ 0xD1, +/* pos 0196: 385 */ /* terminal 182 */ 0xB6, + /* terminal 183 */ 0xB7, +/* pos 0198: 388 */ /* terminal 184 */ 0xB8, + /* terminal 194 */ 0xC2, +/* pos 019a: 390 */ /* terminal 185 */ 0xB9, + /* terminal 186 */ 0xBA, +/* pos 019c: 393 */ /* 0 */ 0x01 /* (to 0x019E state 394) */, + /* 1 */ 0x04 /* (to 0x01A4 state 400) */, +/* pos 019e: 394 */ /* terminal 187 */ 0xBB, + /* terminal 189 */ 0xBD, +/* pos 01a0: 396 */ /* 0 */ 0x01 /* (to 0x01A2 state 397) */, + /* 1 */ 0x07 /* (to 0x01AE state 412) */, +/* pos 01a2: 397 */ /* terminal 188 */ 0xBC, + /* terminal 191 */ 0xBF, +/* pos 01a4: 400 */ /* terminal 190 */ 0xBE, + /* terminal 196 */ 0xC4, +/* pos 01a6: 403 */ /* 0 */ 0x01 /* (to 0x01A8 state 404) */, + /* 1 */ 0x0D /* (to 0x01C0 state 427) */, +/* pos 01a8: 404 */ /* 0 */ 0x01 /* (to 0x01AA state 405) */, + /* 1 */ 0x0A /* (to 0x01BC state 424) */, +/* pos 01aa: 405 */ /* 0 */ 0x01 /* (to 0x01AC state 406) */, + /* 1 */ 0x08 /* (to 0x01BA state 421) */, +/* pos 01ac: 406 */ /* terminal 192 */ 0xC0, + /* terminal 193 */ 0xC1, +/* pos 01ae: 412 */ /* terminal 197 */ 0xC5, + /* terminal 231 */ 0xE7, +/* pos 01b0: 414 */ /* 0 */ 0x01 /* (to 0x01B2 state 415) */, + /* 1 */ 0x1B /* (to 0x01E6 state 475) */, +/* pos 01b2: 415 */ /* terminal 198 */ 0xC6, + /* terminal 228 */ 0xE4, +/* pos 01b4: 417 */ /* 0 */ 0x1B /* (to 0x01EA state 481) */, + /* 1 */ 0x01 /* (to 0x01B6 state 418) */, +/* pos 01b6: 418 */ /* 0 */ 0x01 /* (to 0x01B8 state 419) */, + /* 1 */ 0x19 /* (to 0x01E8 state 478) */, +/* pos 01b8: 419 */ /* terminal 199 */ 0xC7, + /* terminal 207 */ 0xCF, +/* pos 01ba: 421 */ /* terminal 200 */ 0xC8, + /* terminal 201 */ 0xC9, +/* pos 01bc: 424 */ /* 0 */ 0x01 /* (to 0x01BE state 425) */, + /* 1 */ 0x06 /* (to 0x01C8 state 438) */, +/* pos 01be: 425 */ /* terminal 202 */ 0xCA, + /* terminal 205 */ 0xCD, +/* pos 01c0: 427 */ /* 0 */ 0x0D /* (to 0x01DA state 455) */, + /* 1 */ 0x01 /* (to 0x01C2 state 428) */, +/* pos 01c2: 428 */ /* 0 */ 0x17 /* (to 0x01F0 state 490) */, + /* 1 */ 0x01 /* (to 0x01C4 state 429) */, +/* pos 01c4: 429 */ /* terminal 255 */ 0xFF, + /* 1 */ 0x01 /* (to 0x01C6 state 430) */, +/* pos 01c6: 430 */ /* terminal 203 */ 0xCB, + /* terminal 204 */ 0xCC, +/* pos 01c8: 438 */ /* terminal 210 */ 0xD2, + /* terminal 213 */ 0xD5, +/* pos 01ca: 440 */ /* 0 */ 0x01 /* (to 0x01CC state 441) */, + /* 1 */ 0x14 /* (to 0x01F2 state 494) */, +/* pos 01cc: 441 */ /* 0 */ 0x01 /* (to 0x01CE state 442) */, + /* 1 */ 0x09 /* (to 0x01DE state 461) */, +/* pos 01ce: 442 */ /* 0 */ 0x01 /* (to 0x01D0 state 443) */, + /* 1 */ 0x02 /* (to 0x01D2 state 447) */, +/* pos 01d0: 443 */ /* terminal 211 */ 0xD3, + /* terminal 212 */ 0xD4, +/* pos 01d2: 447 */ /* terminal 214 */ 0xD6, + /* terminal 221 */ 0xDD, +/* pos 01d4: 449 */ /* terminal 215 */ 0xD7, + /* terminal 225 */ 0xE1, +/* pos 01d6: 451 */ /* 0 */ 0x01 /* (to 0x01D8 state 452) */, + /* 1 */ 0x07 /* (to 0x01E4 state 469) */, +/* pos 01d8: 452 */ /* terminal 216 */ 0xD8, + /* terminal 217 */ 0xD9, +/* pos 01da: 455 */ /* 0 */ 0x01 /* (to 0x01DC state 456) */, + /* 1 */ 0x09 /* (to 0x01EC state 484) */, +/* pos 01dc: 456 */ /* terminal 218 */ 0xDA, + /* terminal 219 */ 0xDB, +/* pos 01de: 461 */ /* 0 */ 0x01 /* (to 0x01E0 state 462) */, + /* 1 */ 0x08 /* (to 0x01EE state 488) */, +/* pos 01e0: 462 */ /* terminal 222 */ 0xDE, + /* terminal 223 */ 0xDF, +/* pos 01e2: 465 */ /* terminal 224 */ 0xE0, + /* terminal 226 */ 0xE2, +/* pos 01e4: 469 */ /* terminal 227 */ 0xE3, + /* terminal 229 */ 0xE5, +/* pos 01e6: 475 */ /* terminal 232 */ 0xE8, + /* terminal 233 */ 0xE9, +/* pos 01e8: 478 */ /* terminal 234 */ 0xEA, + /* terminal 235 */ 0xEB, +/* pos 01ea: 481 */ /* terminal 236 */ 0xEC, + /* terminal 237 */ 0xED, +/* pos 01ec: 484 */ /* terminal 238 */ 0xEE, + /* terminal 240 */ 0xF0, +/* pos 01ee: 488 */ /* terminal 241 */ 0xF1, + /* terminal 244 */ 0xF4, +/* pos 01f0: 490 */ /* terminal 242 */ 0xF2, + /* terminal 243 */ 0xF3, +/* pos 01f2: 494 */ /* 0 */ 0x01 /* (to 0x01F4 state 495) */, + /* 1 */ 0x04 /* (to 0x01FA state 503) */, +/* pos 01f4: 495 */ /* 0 */ 0x01 /* (to 0x01F6 state 496) */, + /* 1 */ 0x02 /* (to 0x01F8 state 499) */, +/* pos 01f6: 496 */ /* terminal 245 */ 0xF5, + /* terminal 246 */ 0xF6, +/* pos 01f8: 499 */ /* terminal 247 */ 0xF7, + /* terminal 248 */ 0xF8, +/* pos 01fa: 503 */ /* 0 */ 0x01 /* (to 0x01FC state 504) */, + /* 1 */ 0x02 /* (to 0x01FE state 507) */, +/* pos 01fc: 504 */ /* terminal 250 */ 0xFA, + /* terminal 251 */ 0xFB, +/* pos 01fe: 507 */ /* terminal 252 */ 0xFC, + /* terminal 253 */ 0xFD, +/* total size 512 bytes, biggest jump 200/256, fails=0 */ +}; + + static unsigned char lextable_terms[] = { + + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, + 0x34, 0x0f, 0x43, 0x03, 0xf1, 0x3c, 0xfc, 0x3c, + 0x0f, 0x30, 0x37, 0xf7, 0x0f, 0xc3, 0xcf, 0x03, + 0x3c, 0xfc, 0xc0, 0xf3, 0xf0, 0x3c, 0xfc, 0xf0, + 0xcf, 0xfc, 0xcc, 0xff, 0xfc, 0x0d, 0x34, 0xcc, + 0xcf, 0x33, 0xf0, 0x33, 0x0c, 0x3f, 0xc3, 0x3f, + 0xcc, 0x30, 0xfc, 0xcf, 0x3c, 0xf0, 0x0c, 0xcf, + 0xd0, 0x03, 0x3f, 0x33, 0xff, 0xff, 0xc3, 0xf3, +}; + +/* state that points to 0x100 for disambiguation with 0x0 */ +#define HUFTABLE_0x100_PREV 118 diff --git a/src/engine/external/libwebsockets/lextable-strings.h b/src/engine/external/libwebsockets/lextable-strings.h new file mode 100644 index 00000000..c0f1f2ee --- /dev/null +++ b/src/engine/external/libwebsockets/lextable-strings.h @@ -0,0 +1,86 @@ +/* set of parsable strings -- ALL LOWER CASE */ + +static const char *set[] = { + "get ", + "post ", + "options ", + "host:", + "connection:", + "upgrade:", + "origin:", + "sec-websocket-draft:", + "\x0d\x0a", + + "sec-websocket-extensions:", + "sec-websocket-key1:", + "sec-websocket-key2:", + "sec-websocket-protocol:", + + "sec-websocket-accept:", + "sec-websocket-nonce:", + "http/1.1 ", + "http2-settings:", + + "accept:", + "access-control-request-headers:", + "if-modified-since:", + "if-none-match:", + "accept-encoding:", + "accept-language:", + "pragma:", + "cache-control:", + "authorization:", + "cookie:", + "content-length:", + "content-type:", + "date:", + "range:", + "referer:", + "sec-websocket-key:", + "sec-websocket-version:", + "sec-websocket-origin:", + + ":authority:", + ":method:", + ":path:", + ":scheme:", + ":status:", + + "accept-charset:", + "accept-ranges:", + "access-control-allow-origin:", + "age:", + "allow:", + "content-disposition:", + "content-encoding:", + "content-language:", + "content-location:", + "content-range:", + "etag:", + "expect:", + "expires:", + "from:", + "if-match:", + "if-range:", + "if-unmodified-since:", + "last-modified:", + "link:", + "location:", + "max-forwards:", + "proxy-authenticate:", + "proxy-authorization:", + "refresh:", + "retry-after:", + "server:", + "set-cookie:", + "strict-transport-security:", + "transfer-encoding:", + "user-agent:", + "vary:", + "via:", + "www-authenticate:", + "proxy ", + + "", /* not matchable */ + +}; diff --git a/src/engine/external/libwebsockets/lextable.h b/src/engine/external/libwebsockets/lextable.h new file mode 100644 index 00000000..80d318ef --- /dev/null +++ b/src/engine/external/libwebsockets/lextable.h @@ -0,0 +1,745 @@ +/* pos 0000: 0 */ 0x67 /* 'g' */, 0x3D, 0x00 /* (to 0x003D state 1) */, + 0x70 /* 'p' */, 0x3F, 0x00 /* (to 0x0042 state 5) */, + 0x6F /* 'o' */, 0x48, 0x00 /* (to 0x004E state 10) */, + 0x68 /* 'h' */, 0x54, 0x00 /* (to 0x005D state 18) */, + 0x63 /* 'c' */, 0x5D, 0x00 /* (to 0x0069 state 23) */, + 0x75 /* 'u' */, 0x78, 0x00 /* (to 0x0087 state 34) */, + 0x73 /* 's' */, 0x8B, 0x00 /* (to 0x009D state 48) */, + 0x0D /* '.' */, 0xC4, 0x00 /* (to 0x00D9 state 68) */, + 0x61 /* 'a' */, 0x16, 0x01 /* (to 0x012E state 129) */, + 0x69 /* 'i' */, 0x55, 0x01 /* (to 0x0170 state 163) */, + 0x64 /* 'd' */, 0xFE, 0x01 /* (to 0x021C state 265) */, + 0x72 /* 'r' */, 0x01, 0x02 /* (to 0x0222 state 270) */, + 0x3A /* ':' */, 0x32, 0x02 /* (to 0x0256 state 299) */, + 0x65 /* 'e' */, 0xC3, 0x02 /* (to 0x02EA state 414) */, + 0x66 /* 'f' */, 0xDF, 0x02 /* (to 0x0309 state 430) */, + 0x6C /* 'l' */, 0x01, 0x03 /* (to 0x032E state 463) */, + 0x6D /* 'm' */, 0x24, 0x03 /* (to 0x0354 state 489) */, + 0x74 /* 't' */, 0x93, 0x03 /* (to 0x03C6 state 583) */, + 0x76 /* 'v' */, 0xAE, 0x03 /* (to 0x03E4 state 611) */, + 0x77 /* 'w' */, 0xBB, 0x03 /* (to 0x03F4 state 619) */, + 0x08, /* fail */ +/* pos 003d: 1 */ 0xE5 /* 'e' -> */, +/* pos 003e: 2 */ 0xF4 /* 't' -> */, +/* pos 003f: 3 */ 0xA0 /* ' ' -> */, +/* pos 0040: 4 */ 0x00, 0x00 /* - terminal marker 0 - */, +/* pos 0042: 5 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0049 state 6) */, + 0x72 /* 'r' */, 0x7D, 0x01 /* (to 0x01C2 state 211) */, + 0x08, /* fail */ +/* pos 0049: 6 */ 0xF3 /* 's' -> */, +/* pos 004a: 7 */ 0xF4 /* 't' -> */, +/* pos 004b: 8 */ 0xA0 /* ' ' -> */, +/* pos 004c: 9 */ 0x00, 0x01 /* - terminal marker 1 - */, +/* pos 004e: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0055 state 11) */, + 0x72 /* 'r' */, 0x45, 0x00 /* (to 0x0096 state 42) */, + 0x08, /* fail */ +/* pos 0055: 11 */ 0xF4 /* 't' -> */, +/* pos 0056: 12 */ 0xE9 /* 'i' -> */, +/* pos 0057: 13 */ 0xEF /* 'o' -> */, +/* pos 0058: 14 */ 0xEE /* 'n' -> */, +/* pos 0059: 15 */ 0xF3 /* 's' -> */, +/* pos 005a: 16 */ 0xA0 /* ' ' -> */, +/* pos 005b: 17 */ 0x00, 0x02 /* - terminal marker 2 - */, +/* pos 005d: 18 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0064 state 19) */, + 0x74 /* 't' */, 0xB3, 0x00 /* (to 0x0113 state 110) */, + 0x08, /* fail */ +/* pos 0064: 19 */ 0xF3 /* 's' -> */, +/* pos 0065: 20 */ 0xF4 /* 't' -> */, +/* pos 0066: 21 */ 0xBA /* ':' -> */, +/* pos 0067: 22 */ 0x00, 0x03 /* - terminal marker 3 - */, +/* pos 0069: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0070 state 24) */, + 0x61 /* 'a' */, 0x63, 0x01 /* (to 0x01CF state 217) */, + 0x08, /* fail */ +/* pos 0070: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0077 state 25) */, + 0x6F /* 'o' */, 0x78, 0x01 /* (to 0x01EB state 243) */, + 0x08, /* fail */ +/* pos 0077: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x007E state 26) */, + 0x74 /* 't' */, 0x77, 0x01 /* (to 0x01F1 state 248) */, + 0x08, /* fail */ +/* pos 007e: 26 */ 0xE5 /* 'e' -> */, +/* pos 007f: 27 */ 0xE3 /* 'c' -> */, +/* pos 0080: 28 */ 0xF4 /* 't' -> */, +/* pos 0081: 29 */ 0xE9 /* 'i' -> */, +/* pos 0082: 30 */ 0xEF /* 'o' -> */, +/* pos 0083: 31 */ 0xEE /* 'n' -> */, +/* pos 0084: 32 */ 0xBA /* ':' -> */, +/* pos 0085: 33 */ 0x00, 0x04 /* - terminal marker 4 - */, +/* pos 0087: 34 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x008E state 35) */, + 0x73 /* 's' */, 0x4F, 0x03 /* (to 0x03D9 state 601) */, + 0x08, /* fail */ +/* pos 008e: 35 */ 0xE7 /* 'g' -> */, +/* pos 008f: 36 */ 0xF2 /* 'r' -> */, +/* pos 0090: 37 */ 0xE1 /* 'a' -> */, +/* pos 0091: 38 */ 0xE4 /* 'd' -> */, +/* pos 0092: 39 */ 0xE5 /* 'e' -> */, +/* pos 0093: 40 */ 0xBA /* ':' -> */, +/* pos 0094: 41 */ 0x00, 0x05 /* - terminal marker 5 - */, +/* pos 0096: 42 */ 0xE9 /* 'i' -> */, +/* pos 0097: 43 */ 0xE7 /* 'g' -> */, +/* pos 0098: 44 */ 0xE9 /* 'i' -> */, +/* pos 0099: 45 */ 0xEE /* 'n' -> */, +/* pos 009a: 46 */ 0xBA /* ':' -> */, +/* pos 009b: 47 */ 0x00, 0x06 /* - terminal marker 6 - */, +/* pos 009d: 48 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x00A4 state 49) */, + 0x74 /* 't' */, 0x0C, 0x03 /* (to 0x03AC state 558) */, + 0x08, /* fail */ +/* pos 00a4: 49 */ 0x63 /* 'c' */, 0x0A, 0x00 /* (to 0x00AE state 50) */, + 0x72 /* 'r' */, 0xF5, 0x02 /* (to 0x039C state 544) */, + 0x74 /* 't' */, 0xF8, 0x02 /* (to 0x03A2 state 549) */, + 0x08, /* fail */ +/* pos 00ae: 50 */ 0xAD /* '-' -> */, +/* pos 00af: 51 */ 0xF7 /* 'w' -> */, +/* pos 00b0: 52 */ 0xE5 /* 'e' -> */, +/* pos 00b1: 53 */ 0xE2 /* 'b' -> */, +/* pos 00b2: 54 */ 0xF3 /* 's' -> */, +/* pos 00b3: 55 */ 0xEF /* 'o' -> */, +/* pos 00b4: 56 */ 0xE3 /* 'c' -> */, +/* pos 00b5: 57 */ 0xEB /* 'k' -> */, +/* pos 00b6: 58 */ 0xE5 /* 'e' -> */, +/* pos 00b7: 59 */ 0xF4 /* 't' -> */, +/* pos 00b8: 60 */ 0xAD /* '-' -> */, +/* pos 00b9: 61 */ 0x64 /* 'd' */, 0x19, 0x00 /* (to 0x00D2 state 62) */, + 0x65 /* 'e' */, 0x20, 0x00 /* (to 0x00DC state 70) */, + 0x6B /* 'k' */, 0x29, 0x00 /* (to 0x00E8 state 81) */, + 0x70 /* 'p' */, 0x38, 0x00 /* (to 0x00FA state 88) */, + 0x61 /* 'a' */, 0x3F, 0x00 /* (to 0x0104 state 97) */, + 0x6E /* 'n' */, 0x44, 0x00 /* (to 0x010C state 104) */, + 0x76 /* 'v' */, 0x7A, 0x01 /* (to 0x0245 state 284) */, + 0x6F /* 'o' */, 0x80, 0x01 /* (to 0x024E state 292) */, + 0x08, /* fail */ +/* pos 00d2: 62 */ 0xF2 /* 'r' -> */, +/* pos 00d3: 63 */ 0xE1 /* 'a' -> */, +/* pos 00d4: 64 */ 0xE6 /* 'f' -> */, +/* pos 00d5: 65 */ 0xF4 /* 't' -> */, +/* pos 00d6: 66 */ 0xBA /* ':' -> */, +/* pos 00d7: 67 */ 0x00, 0x07 /* - terminal marker 7 - */, +/* pos 00d9: 68 */ 0x8A /* '.' -> */, +/* pos 00da: 69 */ 0x00, 0x08 /* - terminal marker 8 - */, +/* pos 00dc: 70 */ 0xF8 /* 'x' -> */, +/* pos 00dd: 71 */ 0xF4 /* 't' -> */, +/* pos 00de: 72 */ 0xE5 /* 'e' -> */, +/* pos 00df: 73 */ 0xEE /* 'n' -> */, +/* pos 00e0: 74 */ 0xF3 /* 's' -> */, +/* pos 00e1: 75 */ 0xE9 /* 'i' -> */, +/* pos 00e2: 76 */ 0xEF /* 'o' -> */, +/* pos 00e3: 77 */ 0xEE /* 'n' -> */, +/* pos 00e4: 78 */ 0xF3 /* 's' -> */, +/* pos 00e5: 79 */ 0xBA /* ':' -> */, +/* pos 00e6: 80 */ 0x00, 0x09 /* - terminal marker 9 - */, +/* pos 00e8: 81 */ 0xE5 /* 'e' -> */, +/* pos 00e9: 82 */ 0xF9 /* 'y' -> */, +/* pos 00ea: 83 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x00F4 state 84) */, + 0x32 /* '2' */, 0x0A, 0x00 /* (to 0x00F7 state 86) */, + 0x3A /* ':' */, 0x53, 0x01 /* (to 0x0243 state 283) */, + 0x08, /* fail */ +/* pos 00f4: 84 */ 0xBA /* ':' -> */, +/* pos 00f5: 85 */ 0x00, 0x0A /* - terminal marker 10 - */, +/* pos 00f7: 86 */ 0xBA /* ':' -> */, +/* pos 00f8: 87 */ 0x00, 0x0B /* - terminal marker 11 - */, +/* pos 00fa: 88 */ 0xF2 /* 'r' -> */, +/* pos 00fb: 89 */ 0xEF /* 'o' -> */, +/* pos 00fc: 90 */ 0xF4 /* 't' -> */, +/* pos 00fd: 91 */ 0xEF /* 'o' -> */, +/* pos 00fe: 92 */ 0xE3 /* 'c' -> */, +/* pos 00ff: 93 */ 0xEF /* 'o' -> */, +/* pos 0100: 94 */ 0xEC /* 'l' -> */, +/* pos 0101: 95 */ 0xBA /* ':' -> */, +/* pos 0102: 96 */ 0x00, 0x0C /* - terminal marker 12 - */, +/* pos 0104: 97 */ 0xE3 /* 'c' -> */, +/* pos 0105: 98 */ 0xE3 /* 'c' -> */, +/* pos 0106: 99 */ 0xE5 /* 'e' -> */, +/* pos 0107: 100 */ 0xF0 /* 'p' -> */, +/* pos 0108: 101 */ 0xF4 /* 't' -> */, +/* pos 0109: 102 */ 0xBA /* ':' -> */, +/* pos 010a: 103 */ 0x00, 0x0D /* - terminal marker 13 - */, +/* pos 010c: 104 */ 0xEF /* 'o' -> */, +/* pos 010d: 105 */ 0xEE /* 'n' -> */, +/* pos 010e: 106 */ 0xE3 /* 'c' -> */, +/* pos 010f: 107 */ 0xE5 /* 'e' -> */, +/* pos 0110: 108 */ 0xBA /* ':' -> */, +/* pos 0111: 109 */ 0x00, 0x0E /* - terminal marker 14 - */, +/* pos 0113: 110 */ 0xF4 /* 't' -> */, +/* pos 0114: 111 */ 0xF0 /* 'p' -> */, +/* pos 0115: 112 */ 0x2F /* '/' */, 0x07, 0x00 /* (to 0x011C state 113) */, + 0x32 /* '2' */, 0x0A, 0x00 /* (to 0x0122 state 118) */, + 0x08, /* fail */ +/* pos 011c: 113 */ 0xB1 /* '1' -> */, +/* pos 011d: 114 */ 0xAE /* '.' -> */, +/* pos 011e: 115 */ 0xB1 /* '1' -> */, +/* pos 011f: 116 */ 0xA0 /* ' ' -> */, +/* pos 0120: 117 */ 0x00, 0x0F /* - terminal marker 15 - */, +/* pos 0122: 118 */ 0xAD /* '-' -> */, +/* pos 0123: 119 */ 0xF3 /* 's' -> */, +/* pos 0124: 120 */ 0xE5 /* 'e' -> */, +/* pos 0125: 121 */ 0xF4 /* 't' -> */, +/* pos 0126: 122 */ 0xF4 /* 't' -> */, +/* pos 0127: 123 */ 0xE9 /* 'i' -> */, +/* pos 0128: 124 */ 0xEE /* 'n' -> */, +/* pos 0129: 125 */ 0xE7 /* 'g' -> */, +/* pos 012a: 126 */ 0xF3 /* 's' -> */, +/* pos 012b: 127 */ 0xBA /* ':' -> */, +/* pos 012c: 128 */ 0x00, 0x10 /* - terminal marker 16 - */, +/* pos 012e: 129 */ 0x63 /* 'c' */, 0x0D, 0x00 /* (to 0x013B state 130) */, + 0x75 /* 'u' */, 0xAC, 0x00 /* (to 0x01DD state 230) */, + 0x67 /* 'g' */, 0x7C, 0x01 /* (to 0x02B0 state 363) */, + 0x6C /* 'l' */, 0x7D, 0x01 /* (to 0x02B4 state 366) */, + 0x08, /* fail */ +/* pos 013b: 130 */ 0xE3 /* 'c' -> */, +/* pos 013c: 131 */ 0xE5 /* 'e' -> */, +/* pos 013d: 132 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0144 state 133) */, + 0x73 /* 's' */, 0x0E, 0x00 /* (to 0x014E state 136) */, + 0x08, /* fail */ +/* pos 0144: 133 */ 0xF4 /* 't' -> */, +/* pos 0145: 134 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x014C state 135) */, + 0x2D /* '-' */, 0x59, 0x00 /* (to 0x01A1 state 192) */, + 0x08, /* fail */ +/* pos 014c: 135 */ 0x00, 0x11 /* - terminal marker 17 - */, +/* pos 014e: 136 */ 0xF3 /* 's' -> */, +/* pos 014f: 137 */ 0xAD /* '-' -> */, +/* pos 0150: 138 */ 0xE3 /* 'c' -> */, +/* pos 0151: 139 */ 0xEF /* 'o' -> */, +/* pos 0152: 140 */ 0xEE /* 'n' -> */, +/* pos 0153: 141 */ 0xF4 /* 't' -> */, +/* pos 0154: 142 */ 0xF2 /* 'r' -> */, +/* pos 0155: 143 */ 0xEF /* 'o' -> */, +/* pos 0156: 144 */ 0xEC /* 'l' -> */, +/* pos 0157: 145 */ 0xAD /* '-' -> */, +/* pos 0158: 146 */ 0x72 /* 'r' */, 0x07, 0x00 /* (to 0x015F state 147) */, + 0x61 /* 'a' */, 0x47, 0x01 /* (to 0x02A2 state 350) */, + 0x08, /* fail */ +/* pos 015f: 147 */ 0xE5 /* 'e' -> */, +/* pos 0160: 148 */ 0xF1 /* 'q' -> */, +/* pos 0161: 149 */ 0xF5 /* 'u' -> */, +/* pos 0162: 150 */ 0xE5 /* 'e' -> */, +/* pos 0163: 151 */ 0xF3 /* 's' -> */, +/* pos 0164: 152 */ 0xF4 /* 't' -> */, +/* pos 0165: 153 */ 0xAD /* '-' -> */, +/* pos 0166: 154 */ 0xE8 /* 'h' -> */, +/* pos 0167: 155 */ 0xE5 /* 'e' -> */, +/* pos 0168: 156 */ 0xE1 /* 'a' -> */, +/* pos 0169: 157 */ 0xE4 /* 'd' -> */, +/* pos 016a: 158 */ 0xE5 /* 'e' -> */, +/* pos 016b: 159 */ 0xF2 /* 'r' -> */, +/* pos 016c: 160 */ 0xF3 /* 's' -> */, +/* pos 016d: 161 */ 0xBA /* ':' -> */, +/* pos 016e: 162 */ 0x00, 0x12 /* - terminal marker 18 - */, +/* pos 0170: 163 */ 0xE6 /* 'f' -> */, +/* pos 0171: 164 */ 0xAD /* '-' -> */, +/* pos 0172: 165 */ 0x6D /* 'm' */, 0x0D, 0x00 /* (to 0x017F state 166) */, + 0x6E /* 'n' */, 0x20, 0x00 /* (to 0x0195 state 181) */, + 0x72 /* 'r' */, 0x9D, 0x01 /* (to 0x0315 state 440) */, + 0x75 /* 'u' */, 0xA1, 0x01 /* (to 0x031C state 446) */, + 0x08, /* fail */ +/* pos 017f: 166 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0186 state 167) */, + 0x61 /* 'a' */, 0x8D, 0x01 /* (to 0x030F state 435) */, + 0x08, /* fail */ +/* pos 0186: 167 */ 0xE4 /* 'd' -> */, +/* pos 0187: 168 */ 0xE9 /* 'i' -> */, +/* pos 0188: 169 */ 0xE6 /* 'f' -> */, +/* pos 0189: 170 */ 0xE9 /* 'i' -> */, +/* pos 018a: 171 */ 0xE5 /* 'e' -> */, +/* pos 018b: 172 */ 0xE4 /* 'd' -> */, +/* pos 018c: 173 */ 0xAD /* '-' -> */, +/* pos 018d: 174 */ 0xF3 /* 's' -> */, +/* pos 018e: 175 */ 0xE9 /* 'i' -> */, +/* pos 018f: 176 */ 0xEE /* 'n' -> */, +/* pos 0190: 177 */ 0xE3 /* 'c' -> */, +/* pos 0191: 178 */ 0xE5 /* 'e' -> */, +/* pos 0192: 179 */ 0xBA /* ':' -> */, +/* pos 0193: 180 */ 0x00, 0x13 /* - terminal marker 19 - */, +/* pos 0195: 181 */ 0xEF /* 'o' -> */, +/* pos 0196: 182 */ 0xEE /* 'n' -> */, +/* pos 0197: 183 */ 0xE5 /* 'e' -> */, +/* pos 0198: 184 */ 0xAD /* '-' -> */, +/* pos 0199: 185 */ 0xED /* 'm' -> */, +/* pos 019a: 186 */ 0xE1 /* 'a' -> */, +/* pos 019b: 187 */ 0xF4 /* 't' -> */, +/* pos 019c: 188 */ 0xE3 /* 'c' -> */, +/* pos 019d: 189 */ 0xE8 /* 'h' -> */, +/* pos 019e: 190 */ 0xBA /* ':' -> */, +/* pos 019f: 191 */ 0x00, 0x14 /* - terminal marker 20 - */, +/* pos 01a1: 192 */ 0x65 /* 'e' */, 0x0D, 0x00 /* (to 0x01AE state 193) */, + 0x6C /* 'l' */, 0x14, 0x00 /* (to 0x01B8 state 202) */, + 0x63 /* 'c' */, 0xEA, 0x00 /* (to 0x0291 state 335) */, + 0x72 /* 'r' */, 0xF0, 0x00 /* (to 0x029A state 343) */, + 0x08, /* fail */ +/* pos 01ae: 193 */ 0xEE /* 'n' -> */, +/* pos 01af: 194 */ 0xE3 /* 'c' -> */, +/* pos 01b0: 195 */ 0xEF /* 'o' -> */, +/* pos 01b1: 196 */ 0xE4 /* 'd' -> */, +/* pos 01b2: 197 */ 0xE9 /* 'i' -> */, +/* pos 01b3: 198 */ 0xEE /* 'n' -> */, +/* pos 01b4: 199 */ 0xE7 /* 'g' -> */, +/* pos 01b5: 200 */ 0xBA /* ':' -> */, +/* pos 01b6: 201 */ 0x00, 0x15 /* - terminal marker 21 - */, +/* pos 01b8: 202 */ 0xE1 /* 'a' -> */, +/* pos 01b9: 203 */ 0xEE /* 'n' -> */, +/* pos 01ba: 204 */ 0xE7 /* 'g' -> */, +/* pos 01bb: 205 */ 0xF5 /* 'u' -> */, +/* pos 01bc: 206 */ 0xE1 /* 'a' -> */, +/* pos 01bd: 207 */ 0xE7 /* 'g' -> */, +/* pos 01be: 208 */ 0xE5 /* 'e' -> */, +/* pos 01bf: 209 */ 0xBA /* ':' -> */, +/* pos 01c0: 210 */ 0x00, 0x16 /* - terminal marker 22 - */, +/* pos 01c2: 211 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01C9 state 212) */, + 0x6F /* 'o' */, 0x9D, 0x01 /* (to 0x0362 state 502) */, + 0x08, /* fail */ +/* pos 01c9: 212 */ 0xE7 /* 'g' -> */, +/* pos 01ca: 213 */ 0xED /* 'm' -> */, +/* pos 01cb: 214 */ 0xE1 /* 'a' -> */, +/* pos 01cc: 215 */ 0xBA /* ':' -> */, +/* pos 01cd: 216 */ 0x00, 0x17 /* - terminal marker 23 - */, +/* pos 01cf: 217 */ 0xE3 /* 'c' -> */, +/* pos 01d0: 218 */ 0xE8 /* 'h' -> */, +/* pos 01d1: 219 */ 0xE5 /* 'e' -> */, +/* pos 01d2: 220 */ 0xAD /* '-' -> */, +/* pos 01d3: 221 */ 0xE3 /* 'c' -> */, +/* pos 01d4: 222 */ 0xEF /* 'o' -> */, +/* pos 01d5: 223 */ 0xEE /* 'n' -> */, +/* pos 01d6: 224 */ 0xF4 /* 't' -> */, +/* pos 01d7: 225 */ 0xF2 /* 'r' -> */, +/* pos 01d8: 226 */ 0xEF /* 'o' -> */, +/* pos 01d9: 227 */ 0xEC /* 'l' -> */, +/* pos 01da: 228 */ 0xBA /* ':' -> */, +/* pos 01db: 229 */ 0x00, 0x18 /* - terminal marker 24 - */, +/* pos 01dd: 230 */ 0xF4 /* 't' -> */, +/* pos 01de: 231 */ 0xE8 /* 'h' -> */, +/* pos 01df: 232 */ 0xEF /* 'o' -> */, +/* pos 01e0: 233 */ 0xF2 /* 'r' -> */, +/* pos 01e1: 234 */ 0xE9 /* 'i' -> */, +/* pos 01e2: 235 */ 0xFA /* 'z' -> */, +/* pos 01e3: 236 */ 0xE1 /* 'a' -> */, +/* pos 01e4: 237 */ 0xF4 /* 't' -> */, +/* pos 01e5: 238 */ 0xE9 /* 'i' -> */, +/* pos 01e6: 239 */ 0xEF /* 'o' -> */, +/* pos 01e7: 240 */ 0xEE /* 'n' -> */, +/* pos 01e8: 241 */ 0xBA /* ':' -> */, +/* pos 01e9: 242 */ 0x00, 0x19 /* - terminal marker 25 - */, +/* pos 01eb: 243 */ 0xEB /* 'k' -> */, +/* pos 01ec: 244 */ 0xE9 /* 'i' -> */, +/* pos 01ed: 245 */ 0xE5 /* 'e' -> */, +/* pos 01ee: 246 */ 0xBA /* ':' -> */, +/* pos 01ef: 247 */ 0x00, 0x1A /* - terminal marker 26 - */, +/* pos 01f1: 248 */ 0xE5 /* 'e' -> */, +/* pos 01f2: 249 */ 0xEE /* 'n' -> */, +/* pos 01f3: 250 */ 0xF4 /* 't' -> */, +/* pos 01f4: 251 */ 0xAD /* '-' -> */, +/* pos 01f5: 252 */ 0x6C /* 'l' */, 0x10, 0x00 /* (to 0x0205 state 253) */, + 0x74 /* 't' */, 0x1E, 0x00 /* (to 0x0216 state 260) */, + 0x64 /* 'd' */, 0xBF, 0x00 /* (to 0x02BA state 371) */, + 0x65 /* 'e' */, 0xC9, 0x00 /* (to 0x02C7 state 383) */, + 0x72 /* 'r' */, 0xE2, 0x00 /* (to 0x02E3 state 408) */, + 0x08, /* fail */ +/* pos 0205: 253 */ 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x020F state 254) */, + 0x61 /* 'a' */, 0xC9, 0x00 /* (to 0x02D1 state 392) */, + 0x6F /* 'o' */, 0xCF, 0x00 /* (to 0x02DA state 400) */, + 0x08, /* fail */ +/* pos 020f: 254 */ 0xEE /* 'n' -> */, +/* pos 0210: 255 */ 0xE7 /* 'g' -> */, +/* pos 0211: 256 */ 0xF4 /* 't' -> */, +/* pos 0212: 257 */ 0xE8 /* 'h' -> */, +/* pos 0213: 258 */ 0xBA /* ':' -> */, +/* pos 0214: 259 */ 0x00, 0x1B /* - terminal marker 27 - */, +/* pos 0216: 260 */ 0xF9 /* 'y' -> */, +/* pos 0217: 261 */ 0xF0 /* 'p' -> */, +/* pos 0218: 262 */ 0xE5 /* 'e' -> */, +/* pos 0219: 263 */ 0xBA /* ':' -> */, +/* pos 021a: 264 */ 0x00, 0x1C /* - terminal marker 28 - */, +/* pos 021c: 265 */ 0xE1 /* 'a' -> */, +/* pos 021d: 266 */ 0xF4 /* 't' -> */, +/* pos 021e: 267 */ 0xE5 /* 'e' -> */, +/* pos 021f: 268 */ 0xBA /* ':' -> */, +/* pos 0220: 269 */ 0x00, 0x1D /* - terminal marker 29 - */, +/* pos 0222: 270 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0229 state 271) */, + 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x022F state 276) */, + 0x08, /* fail */ +/* pos 0229: 271 */ 0xEE /* 'n' -> */, +/* pos 022a: 272 */ 0xE7 /* 'g' -> */, +/* pos 022b: 273 */ 0xE5 /* 'e' -> */, +/* pos 022c: 274 */ 0xBA /* ':' -> */, +/* pos 022d: 275 */ 0x00, 0x1E /* - terminal marker 30 - */, +/* pos 022f: 276 */ 0x66 /* 'f' */, 0x07, 0x00 /* (to 0x0236 state 277) */, + 0x74 /* 't' */, 0x5F, 0x01 /* (to 0x0391 state 534) */, + 0x08, /* fail */ +/* pos 0236: 277 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x023D state 278) */, + 0x72 /* 'r' */, 0x52, 0x01 /* (to 0x038B state 529) */, + 0x08, /* fail */ +/* pos 023d: 278 */ 0xF2 /* 'r' -> */, +/* pos 023e: 279 */ 0xE5 /* 'e' -> */, +/* pos 023f: 280 */ 0xF2 /* 'r' -> */, +/* pos 0240: 281 */ 0xBA /* ':' -> */, +/* pos 0241: 282 */ 0x00, 0x1F /* - terminal marker 31 - */, +/* pos 0243: 283 */ 0x00, 0x20 /* - terminal marker 32 - */, +/* pos 0245: 284 */ 0xE5 /* 'e' -> */, +/* pos 0246: 285 */ 0xF2 /* 'r' -> */, +/* pos 0247: 286 */ 0xF3 /* 's' -> */, +/* pos 0248: 287 */ 0xE9 /* 'i' -> */, +/* pos 0249: 288 */ 0xEF /* 'o' -> */, +/* pos 024a: 289 */ 0xEE /* 'n' -> */, +/* pos 024b: 290 */ 0xBA /* ':' -> */, +/* pos 024c: 291 */ 0x00, 0x21 /* - terminal marker 33 - */, +/* pos 024e: 292 */ 0xF2 /* 'r' -> */, +/* pos 024f: 293 */ 0xE9 /* 'i' -> */, +/* pos 0250: 294 */ 0xE7 /* 'g' -> */, +/* pos 0251: 295 */ 0xE9 /* 'i' -> */, +/* pos 0252: 296 */ 0xEE /* 'n' -> */, +/* pos 0253: 297 */ 0xBA /* ':' -> */, +/* pos 0254: 298 */ 0x00, 0x22 /* - terminal marker 34 - */, +/* pos 0256: 299 */ 0x61 /* 'a' */, 0x0D, 0x00 /* (to 0x0263 state 300) */, + 0x6D /* 'm' */, 0x15, 0x00 /* (to 0x026E state 310) */, + 0x70 /* 'p' */, 0x1A, 0x00 /* (to 0x0276 state 317) */, + 0x73 /* 's' */, 0x1D, 0x00 /* (to 0x027C state 322) */, + 0x08, /* fail */ +/* pos 0263: 300 */ 0xF5 /* 'u' -> */, +/* pos 0264: 301 */ 0xF4 /* 't' -> */, +/* pos 0265: 302 */ 0xE8 /* 'h' -> */, +/* pos 0266: 303 */ 0xEF /* 'o' -> */, +/* pos 0267: 304 */ 0xF2 /* 'r' -> */, +/* pos 0268: 305 */ 0xE9 /* 'i' -> */, +/* pos 0269: 306 */ 0xF4 /* 't' -> */, +/* pos 026a: 307 */ 0xF9 /* 'y' -> */, +/* pos 026b: 308 */ 0xBA /* ':' -> */, +/* pos 026c: 309 */ 0x00, 0x23 /* - terminal marker 35 - */, +/* pos 026e: 310 */ 0xE5 /* 'e' -> */, +/* pos 026f: 311 */ 0xF4 /* 't' -> */, +/* pos 0270: 312 */ 0xE8 /* 'h' -> */, +/* pos 0271: 313 */ 0xEF /* 'o' -> */, +/* pos 0272: 314 */ 0xE4 /* 'd' -> */, +/* pos 0273: 315 */ 0xBA /* ':' -> */, +/* pos 0274: 316 */ 0x00, 0x24 /* - terminal marker 36 - */, +/* pos 0276: 317 */ 0xE1 /* 'a' -> */, +/* pos 0277: 318 */ 0xF4 /* 't' -> */, +/* pos 0278: 319 */ 0xE8 /* 'h' -> */, +/* pos 0279: 320 */ 0xBA /* ':' -> */, +/* pos 027a: 321 */ 0x00, 0x25 /* - terminal marker 37 - */, +/* pos 027c: 322 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x0283 state 323) */, + 0x74 /* 't' */, 0x0B, 0x00 /* (to 0x028A state 329) */, + 0x08, /* fail */ +/* pos 0283: 323 */ 0xE8 /* 'h' -> */, +/* pos 0284: 324 */ 0xE5 /* 'e' -> */, +/* pos 0285: 325 */ 0xED /* 'm' -> */, +/* pos 0286: 326 */ 0xE5 /* 'e' -> */, +/* pos 0287: 327 */ 0xBA /* ':' -> */, +/* pos 0288: 328 */ 0x00, 0x26 /* - terminal marker 38 - */, +/* pos 028a: 329 */ 0xE1 /* 'a' -> */, +/* pos 028b: 330 */ 0xF4 /* 't' -> */, +/* pos 028c: 331 */ 0xF5 /* 'u' -> */, +/* pos 028d: 332 */ 0xF3 /* 's' -> */, +/* pos 028e: 333 */ 0xBA /* ':' -> */, +/* pos 028f: 334 */ 0x00, 0x27 /* - terminal marker 39 - */, +/* pos 0291: 335 */ 0xE8 /* 'h' -> */, +/* pos 0292: 336 */ 0xE1 /* 'a' -> */, +/* pos 0293: 337 */ 0xF2 /* 'r' -> */, +/* pos 0294: 338 */ 0xF3 /* 's' -> */, +/* pos 0295: 339 */ 0xE5 /* 'e' -> */, +/* pos 0296: 340 */ 0xF4 /* 't' -> */, +/* pos 0297: 341 */ 0xBA /* ':' -> */, +/* pos 0298: 342 */ 0x00, 0x28 /* - terminal marker 40 - */, +/* pos 029a: 343 */ 0xE1 /* 'a' -> */, +/* pos 029b: 344 */ 0xEE /* 'n' -> */, +/* pos 029c: 345 */ 0xE7 /* 'g' -> */, +/* pos 029d: 346 */ 0xE5 /* 'e' -> */, +/* pos 029e: 347 */ 0xF3 /* 's' -> */, +/* pos 029f: 348 */ 0xBA /* ':' -> */, +/* pos 02a0: 349 */ 0x00, 0x29 /* - terminal marker 41 - */, +/* pos 02a2: 350 */ 0xEC /* 'l' -> */, +/* pos 02a3: 351 */ 0xEC /* 'l' -> */, +/* pos 02a4: 352 */ 0xEF /* 'o' -> */, +/* pos 02a5: 353 */ 0xF7 /* 'w' -> */, +/* pos 02a6: 354 */ 0xAD /* '-' -> */, +/* pos 02a7: 355 */ 0xEF /* 'o' -> */, +/* pos 02a8: 356 */ 0xF2 /* 'r' -> */, +/* pos 02a9: 357 */ 0xE9 /* 'i' -> */, +/* pos 02aa: 358 */ 0xE7 /* 'g' -> */, +/* pos 02ab: 359 */ 0xE9 /* 'i' -> */, +/* pos 02ac: 360 */ 0xEE /* 'n' -> */, +/* pos 02ad: 361 */ 0xBA /* ':' -> */, +/* pos 02ae: 362 */ 0x00, 0x2A /* - terminal marker 42 - */, +/* pos 02b0: 363 */ 0xE5 /* 'e' -> */, +/* pos 02b1: 364 */ 0xBA /* ':' -> */, +/* pos 02b2: 365 */ 0x00, 0x2B /* - terminal marker 43 - */, +/* pos 02b4: 366 */ 0xEC /* 'l' -> */, +/* pos 02b5: 367 */ 0xEF /* 'o' -> */, +/* pos 02b6: 368 */ 0xF7 /* 'w' -> */, +/* pos 02b7: 369 */ 0xBA /* ':' -> */, +/* pos 02b8: 370 */ 0x00, 0x2C /* - terminal marker 44 - */, +/* pos 02ba: 371 */ 0xE9 /* 'i' -> */, +/* pos 02bb: 372 */ 0xF3 /* 's' -> */, +/* pos 02bc: 373 */ 0xF0 /* 'p' -> */, +/* pos 02bd: 374 */ 0xEF /* 'o' -> */, +/* pos 02be: 375 */ 0xF3 /* 's' -> */, +/* pos 02bf: 376 */ 0xE9 /* 'i' -> */, +/* pos 02c0: 377 */ 0xF4 /* 't' -> */, +/* pos 02c1: 378 */ 0xE9 /* 'i' -> */, +/* pos 02c2: 379 */ 0xEF /* 'o' -> */, +/* pos 02c3: 380 */ 0xEE /* 'n' -> */, +/* pos 02c4: 381 */ 0xBA /* ':' -> */, +/* pos 02c5: 382 */ 0x00, 0x2D /* - terminal marker 45 - */, +/* pos 02c7: 383 */ 0xEE /* 'n' -> */, +/* pos 02c8: 384 */ 0xE3 /* 'c' -> */, +/* pos 02c9: 385 */ 0xEF /* 'o' -> */, +/* pos 02ca: 386 */ 0xE4 /* 'd' -> */, +/* pos 02cb: 387 */ 0xE9 /* 'i' -> */, +/* pos 02cc: 388 */ 0xEE /* 'n' -> */, +/* pos 02cd: 389 */ 0xE7 /* 'g' -> */, +/* pos 02ce: 390 */ 0xBA /* ':' -> */, +/* pos 02cf: 391 */ 0x00, 0x2E /* - terminal marker 46 - */, +/* pos 02d1: 392 */ 0xEE /* 'n' -> */, +/* pos 02d2: 393 */ 0xE7 /* 'g' -> */, +/* pos 02d3: 394 */ 0xF5 /* 'u' -> */, +/* pos 02d4: 395 */ 0xE1 /* 'a' -> */, +/* pos 02d5: 396 */ 0xE7 /* 'g' -> */, +/* pos 02d6: 397 */ 0xE5 /* 'e' -> */, +/* pos 02d7: 398 */ 0xBA /* ':' -> */, +/* pos 02d8: 399 */ 0x00, 0x2F /* - terminal marker 47 - */, +/* pos 02da: 400 */ 0xE3 /* 'c' -> */, +/* pos 02db: 401 */ 0xE1 /* 'a' -> */, +/* pos 02dc: 402 */ 0xF4 /* 't' -> */, +/* pos 02dd: 403 */ 0xE9 /* 'i' -> */, +/* pos 02de: 404 */ 0xEF /* 'o' -> */, +/* pos 02df: 405 */ 0xEE /* 'n' -> */, +/* pos 02e0: 406 */ 0xBA /* ':' -> */, +/* pos 02e1: 407 */ 0x00, 0x30 /* - terminal marker 48 - */, +/* pos 02e3: 408 */ 0xE1 /* 'a' -> */, +/* pos 02e4: 409 */ 0xEE /* 'n' -> */, +/* pos 02e5: 410 */ 0xE7 /* 'g' -> */, +/* pos 02e6: 411 */ 0xE5 /* 'e' -> */, +/* pos 02e7: 412 */ 0xBA /* ':' -> */, +/* pos 02e8: 413 */ 0x00, 0x31 /* - terminal marker 49 - */, +/* pos 02ea: 414 */ 0x74 /* 't' */, 0x07, 0x00 /* (to 0x02F1 state 415) */, + 0x78 /* 'x' */, 0x09, 0x00 /* (to 0x02F6 state 419) */, + 0x08, /* fail */ +/* pos 02f1: 415 */ 0xE1 /* 'a' -> */, +/* pos 02f2: 416 */ 0xE7 /* 'g' -> */, +/* pos 02f3: 417 */ 0xBA /* ':' -> */, +/* pos 02f4: 418 */ 0x00, 0x32 /* - terminal marker 50 - */, +/* pos 02f6: 419 */ 0xF0 /* 'p' -> */, +/* pos 02f7: 420 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x02FE state 421) */, + 0x69 /* 'i' */, 0x09, 0x00 /* (to 0x0303 state 425) */, + 0x08, /* fail */ +/* pos 02fe: 421 */ 0xE3 /* 'c' -> */, +/* pos 02ff: 422 */ 0xF4 /* 't' -> */, +/* pos 0300: 423 */ 0xBA /* ':' -> */, +/* pos 0301: 424 */ 0x00, 0x33 /* - terminal marker 51 - */, +/* pos 0303: 425 */ 0xF2 /* 'r' -> */, +/* pos 0304: 426 */ 0xE5 /* 'e' -> */, +/* pos 0305: 427 */ 0xF3 /* 's' -> */, +/* pos 0306: 428 */ 0xBA /* ':' -> */, +/* pos 0307: 429 */ 0x00, 0x34 /* - terminal marker 52 - */, +/* pos 0309: 430 */ 0xF2 /* 'r' -> */, +/* pos 030a: 431 */ 0xEF /* 'o' -> */, +/* pos 030b: 432 */ 0xED /* 'm' -> */, +/* pos 030c: 433 */ 0xBA /* ':' -> */, +/* pos 030d: 434 */ 0x00, 0x35 /* - terminal marker 53 - */, +/* pos 030f: 435 */ 0xF4 /* 't' -> */, +/* pos 0310: 436 */ 0xE3 /* 'c' -> */, +/* pos 0311: 437 */ 0xE8 /* 'h' -> */, +/* pos 0312: 438 */ 0xBA /* ':' -> */, +/* pos 0313: 439 */ 0x00, 0x36 /* - terminal marker 54 - */, +/* pos 0315: 440 */ 0xE1 /* 'a' -> */, +/* pos 0316: 441 */ 0xEE /* 'n' -> */, +/* pos 0317: 442 */ 0xE7 /* 'g' -> */, +/* pos 0318: 443 */ 0xE5 /* 'e' -> */, +/* pos 0319: 444 */ 0xBA /* ':' -> */, +/* pos 031a: 445 */ 0x00, 0x37 /* - terminal marker 55 - */, +/* pos 031c: 446 */ 0xEE /* 'n' -> */, +/* pos 031d: 447 */ 0xED /* 'm' -> */, +/* pos 031e: 448 */ 0xEF /* 'o' -> */, +/* pos 031f: 449 */ 0xE4 /* 'd' -> */, +/* pos 0320: 450 */ 0xE9 /* 'i' -> */, +/* pos 0321: 451 */ 0xE6 /* 'f' -> */, +/* pos 0322: 452 */ 0xE9 /* 'i' -> */, +/* pos 0323: 453 */ 0xE5 /* 'e' -> */, +/* pos 0324: 454 */ 0xE4 /* 'd' -> */, +/* pos 0325: 455 */ 0xAD /* '-' -> */, +/* pos 0326: 456 */ 0xF3 /* 's' -> */, +/* pos 0327: 457 */ 0xE9 /* 'i' -> */, +/* pos 0328: 458 */ 0xEE /* 'n' -> */, +/* pos 0329: 459 */ 0xE3 /* 'c' -> */, +/* pos 032a: 460 */ 0xE5 /* 'e' -> */, +/* pos 032b: 461 */ 0xBA /* ':' -> */, +/* pos 032c: 462 */ 0x00, 0x38 /* - terminal marker 56 - */, +/* pos 032e: 463 */ 0x61 /* 'a' */, 0x0A, 0x00 /* (to 0x0338 state 464) */, + 0x69 /* 'i' */, 0x15, 0x00 /* (to 0x0346 state 477) */, + 0x6F /* 'o' */, 0x17, 0x00 /* (to 0x034B state 481) */, + 0x08, /* fail */ +/* pos 0338: 464 */ 0xF3 /* 's' -> */, +/* pos 0339: 465 */ 0xF4 /* 't' -> */, +/* pos 033a: 466 */ 0xAD /* '-' -> */, +/* pos 033b: 467 */ 0xED /* 'm' -> */, +/* pos 033c: 468 */ 0xEF /* 'o' -> */, +/* pos 033d: 469 */ 0xE4 /* 'd' -> */, +/* pos 033e: 470 */ 0xE9 /* 'i' -> */, +/* pos 033f: 471 */ 0xE6 /* 'f' -> */, +/* pos 0340: 472 */ 0xE9 /* 'i' -> */, +/* pos 0341: 473 */ 0xE5 /* 'e' -> */, +/* pos 0342: 474 */ 0xE4 /* 'd' -> */, +/* pos 0343: 475 */ 0xBA /* ':' -> */, +/* pos 0344: 476 */ 0x00, 0x39 /* - terminal marker 57 - */, +/* pos 0346: 477 */ 0xEE /* 'n' -> */, +/* pos 0347: 478 */ 0xEB /* 'k' -> */, +/* pos 0348: 479 */ 0xBA /* ':' -> */, +/* pos 0349: 480 */ 0x00, 0x3A /* - terminal marker 58 - */, +/* pos 034b: 481 */ 0xE3 /* 'c' -> */, +/* pos 034c: 482 */ 0xE1 /* 'a' -> */, +/* pos 034d: 483 */ 0xF4 /* 't' -> */, +/* pos 034e: 484 */ 0xE9 /* 'i' -> */, +/* pos 034f: 485 */ 0xEF /* 'o' -> */, +/* pos 0350: 486 */ 0xEE /* 'n' -> */, +/* pos 0351: 487 */ 0xBA /* ':' -> */, +/* pos 0352: 488 */ 0x00, 0x3B /* - terminal marker 59 - */, +/* pos 0354: 489 */ 0xE1 /* 'a' -> */, +/* pos 0355: 490 */ 0xF8 /* 'x' -> */, +/* pos 0356: 491 */ 0xAD /* '-' -> */, +/* pos 0357: 492 */ 0xE6 /* 'f' -> */, +/* pos 0358: 493 */ 0xEF /* 'o' -> */, +/* pos 0359: 494 */ 0xF2 /* 'r' -> */, +/* pos 035a: 495 */ 0xF7 /* 'w' -> */, +/* pos 035b: 496 */ 0xE1 /* 'a' -> */, +/* pos 035c: 497 */ 0xF2 /* 'r' -> */, +/* pos 035d: 498 */ 0xE4 /* 'd' -> */, +/* pos 035e: 499 */ 0xF3 /* 's' -> */, +/* pos 035f: 500 */ 0xBA /* ':' -> */, +/* pos 0360: 501 */ 0x00, 0x3C /* - terminal marker 60 - */, +/* pos 0362: 502 */ 0xF8 /* 'x' -> */, +/* pos 0363: 503 */ 0xF9 /* 'y' -> */, +/* pos 0364: 504 */ 0x2D /* '-' */, 0x07, 0x00 /* (to 0x036B state 505) */, + 0x20 /* ' ' */, 0x9F, 0x00 /* (to 0x0406 state 636) */, + 0x08, /* fail */ +/* pos 036b: 505 */ 0xE1 /* 'a' -> */, +/* pos 036c: 506 */ 0xF5 /* 'u' -> */, +/* pos 036d: 507 */ 0xF4 /* 't' -> */, +/* pos 036e: 508 */ 0xE8 /* 'h' -> */, +/* pos 036f: 509 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0376 state 510) */, + 0x6F /* 'o' */, 0x0E, 0x00 /* (to 0x0380 state 519) */, + 0x08, /* fail */ +/* pos 0376: 510 */ 0xEE /* 'n' -> */, +/* pos 0377: 511 */ 0xF4 /* 't' -> */, +/* pos 0378: 512 */ 0xE9 /* 'i' -> */, +/* pos 0379: 513 */ 0xE3 /* 'c' -> */, +/* pos 037a: 514 */ 0xE1 /* 'a' -> */, +/* pos 037b: 515 */ 0xF4 /* 't' -> */, +/* pos 037c: 516 */ 0xE5 /* 'e' -> */, +/* pos 037d: 517 */ 0xBA /* ':' -> */, +/* pos 037e: 518 */ 0x00, 0x3D /* - terminal marker 61 - */, +/* pos 0380: 519 */ 0xF2 /* 'r' -> */, +/* pos 0381: 520 */ 0xE9 /* 'i' -> */, +/* pos 0382: 521 */ 0xFA /* 'z' -> */, +/* pos 0383: 522 */ 0xE1 /* 'a' -> */, +/* pos 0384: 523 */ 0xF4 /* 't' -> */, +/* pos 0385: 524 */ 0xE9 /* 'i' -> */, +/* pos 0386: 525 */ 0xEF /* 'o' -> */, +/* pos 0387: 526 */ 0xEE /* 'n' -> */, +/* pos 0388: 527 */ 0xBA /* ':' -> */, +/* pos 0389: 528 */ 0x00, 0x3E /* - terminal marker 62 - */, +/* pos 038b: 529 */ 0xE5 /* 'e' -> */, +/* pos 038c: 530 */ 0xF3 /* 's' -> */, +/* pos 038d: 531 */ 0xE8 /* 'h' -> */, +/* pos 038e: 532 */ 0xBA /* ':' -> */, +/* pos 038f: 533 */ 0x00, 0x3F /* - terminal marker 63 - */, +/* pos 0391: 534 */ 0xF2 /* 'r' -> */, +/* pos 0392: 535 */ 0xF9 /* 'y' -> */, +/* pos 0393: 536 */ 0xAD /* '-' -> */, +/* pos 0394: 537 */ 0xE1 /* 'a' -> */, +/* pos 0395: 538 */ 0xE6 /* 'f' -> */, +/* pos 0396: 539 */ 0xF4 /* 't' -> */, +/* pos 0397: 540 */ 0xE5 /* 'e' -> */, +/* pos 0398: 541 */ 0xF2 /* 'r' -> */, +/* pos 0399: 542 */ 0xBA /* ':' -> */, +/* pos 039a: 543 */ 0x00, 0x40 /* - terminal marker 64 - */, +/* pos 039c: 544 */ 0xF6 /* 'v' -> */, +/* pos 039d: 545 */ 0xE5 /* 'e' -> */, +/* pos 039e: 546 */ 0xF2 /* 'r' -> */, +/* pos 039f: 547 */ 0xBA /* ':' -> */, +/* pos 03a0: 548 */ 0x00, 0x41 /* - terminal marker 65 - */, +/* pos 03a2: 549 */ 0xAD /* '-' -> */, +/* pos 03a3: 550 */ 0xE3 /* 'c' -> */, +/* pos 03a4: 551 */ 0xEF /* 'o' -> */, +/* pos 03a5: 552 */ 0xEF /* 'o' -> */, +/* pos 03a6: 553 */ 0xEB /* 'k' -> */, +/* pos 03a7: 554 */ 0xE9 /* 'i' -> */, +/* pos 03a8: 555 */ 0xE5 /* 'e' -> */, +/* pos 03a9: 556 */ 0xBA /* ':' -> */, +/* pos 03aa: 557 */ 0x00, 0x42 /* - terminal marker 66 - */, +/* pos 03ac: 558 */ 0xF2 /* 'r' -> */, +/* pos 03ad: 559 */ 0xE9 /* 'i' -> */, +/* pos 03ae: 560 */ 0xE3 /* 'c' -> */, +/* pos 03af: 561 */ 0xF4 /* 't' -> */, +/* pos 03b0: 562 */ 0xAD /* '-' -> */, +/* pos 03b1: 563 */ 0xF4 /* 't' -> */, +/* pos 03b2: 564 */ 0xF2 /* 'r' -> */, +/* pos 03b3: 565 */ 0xE1 /* 'a' -> */, +/* pos 03b4: 566 */ 0xEE /* 'n' -> */, +/* pos 03b5: 567 */ 0xF3 /* 's' -> */, +/* pos 03b6: 568 */ 0xF0 /* 'p' -> */, +/* pos 03b7: 569 */ 0xEF /* 'o' -> */, +/* pos 03b8: 570 */ 0xF2 /* 'r' -> */, +/* pos 03b9: 571 */ 0xF4 /* 't' -> */, +/* pos 03ba: 572 */ 0xAD /* '-' -> */, +/* pos 03bb: 573 */ 0xF3 /* 's' -> */, +/* pos 03bc: 574 */ 0xE5 /* 'e' -> */, +/* pos 03bd: 575 */ 0xE3 /* 'c' -> */, +/* pos 03be: 576 */ 0xF5 /* 'u' -> */, +/* pos 03bf: 577 */ 0xF2 /* 'r' -> */, +/* pos 03c0: 578 */ 0xE9 /* 'i' -> */, +/* pos 03c1: 579 */ 0xF4 /* 't' -> */, +/* pos 03c2: 580 */ 0xF9 /* 'y' -> */, +/* pos 03c3: 581 */ 0xBA /* ':' -> */, +/* pos 03c4: 582 */ 0x00, 0x43 /* - terminal marker 67 - */, +/* pos 03c6: 583 */ 0xF2 /* 'r' -> */, +/* pos 03c7: 584 */ 0xE1 /* 'a' -> */, +/* pos 03c8: 585 */ 0xEE /* 'n' -> */, +/* pos 03c9: 586 */ 0xF3 /* 's' -> */, +/* pos 03ca: 587 */ 0xE6 /* 'f' -> */, +/* pos 03cb: 588 */ 0xE5 /* 'e' -> */, +/* pos 03cc: 589 */ 0xF2 /* 'r' -> */, +/* pos 03cd: 590 */ 0xAD /* '-' -> */, +/* pos 03ce: 591 */ 0xE5 /* 'e' -> */, +/* pos 03cf: 592 */ 0xEE /* 'n' -> */, +/* pos 03d0: 593 */ 0xE3 /* 'c' -> */, +/* pos 03d1: 594 */ 0xEF /* 'o' -> */, +/* pos 03d2: 595 */ 0xE4 /* 'd' -> */, +/* pos 03d3: 596 */ 0xE9 /* 'i' -> */, +/* pos 03d4: 597 */ 0xEE /* 'n' -> */, +/* pos 03d5: 598 */ 0xE7 /* 'g' -> */, +/* pos 03d6: 599 */ 0xBA /* ':' -> */, +/* pos 03d7: 600 */ 0x00, 0x44 /* - terminal marker 68 - */, +/* pos 03d9: 601 */ 0xE5 /* 'e' -> */, +/* pos 03da: 602 */ 0xF2 /* 'r' -> */, +/* pos 03db: 603 */ 0xAD /* '-' -> */, +/* pos 03dc: 604 */ 0xE1 /* 'a' -> */, +/* pos 03dd: 605 */ 0xE7 /* 'g' -> */, +/* pos 03de: 606 */ 0xE5 /* 'e' -> */, +/* pos 03df: 607 */ 0xEE /* 'n' -> */, +/* pos 03e0: 608 */ 0xF4 /* 't' -> */, +/* pos 03e1: 609 */ 0xBA /* ':' -> */, +/* pos 03e2: 610 */ 0x00, 0x45 /* - terminal marker 69 - */, +/* pos 03e4: 611 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x03EB state 612) */, + 0x69 /* 'i' */, 0x09, 0x00 /* (to 0x03F0 state 616) */, + 0x08, /* fail */ +/* pos 03eb: 612 */ 0xF2 /* 'r' -> */, +/* pos 03ec: 613 */ 0xF9 /* 'y' -> */, +/* pos 03ed: 614 */ 0xBA /* ':' -> */, +/* pos 03ee: 615 */ 0x00, 0x46 /* - terminal marker 70 - */, +/* pos 03f0: 616 */ 0xE1 /* 'a' -> */, +/* pos 03f1: 617 */ 0xBA /* ':' -> */, +/* pos 03f2: 618 */ 0x00, 0x47 /* - terminal marker 71 - */, +/* pos 03f4: 619 */ 0xF7 /* 'w' -> */, +/* pos 03f5: 620 */ 0xF7 /* 'w' -> */, +/* pos 03f6: 621 */ 0xAD /* '-' -> */, +/* pos 03f7: 622 */ 0xE1 /* 'a' -> */, +/* pos 03f8: 623 */ 0xF5 /* 'u' -> */, +/* pos 03f9: 624 */ 0xF4 /* 't' -> */, +/* pos 03fa: 625 */ 0xE8 /* 'h' -> */, +/* pos 03fb: 626 */ 0xE5 /* 'e' -> */, +/* pos 03fc: 627 */ 0xEE /* 'n' -> */, +/* pos 03fd: 628 */ 0xF4 /* 't' -> */, +/* pos 03fe: 629 */ 0xE9 /* 'i' -> */, +/* pos 03ff: 630 */ 0xE3 /* 'c' -> */, +/* pos 0400: 631 */ 0xE1 /* 'a' -> */, +/* pos 0401: 632 */ 0xF4 /* 't' -> */, +/* pos 0402: 633 */ 0xE5 /* 'e' -> */, +/* pos 0403: 634 */ 0xBA /* ':' -> */, +/* pos 0404: 635 */ 0x00, 0x48 /* - terminal marker 72 - */, +/* pos 0406: 636 */ 0x00, 0x49 /* - terminal marker 73 - */, +/* total size 1032 bytes */ diff --git a/src/engine/external/libwebsockets/libwebsockets.c b/src/engine/external/libwebsockets/libwebsockets.c new file mode 100644 index 00000000..b9be442f --- /dev/null +++ b/src/engine/external/libwebsockets/libwebsockets.c @@ -0,0 +1,850 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE; +static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr; + +static const char * const log_level_names[] = { + "ERR", + "WARN", + "NOTICE", + "INFO", + "DEBUG", + "PARSER", + "HEADER", + "EXTENSION", + "CLIENT", + "LATENCY", +}; + + +void +libwebsocket_close_and_free_session(struct libwebsocket_context *context, + struct libwebsocket *wsi, enum lws_close_status reason) +{ + int n, m, ret; + int old_state; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 + + LWS_SEND_BUFFER_POST_PADDING]; + struct lws_tokens eff_buf; + + if (!wsi) + return; + + old_state = wsi->state; + + if (wsi->socket_is_permanently_unusable) + goto just_kill_connection; + + switch (old_state) { + case WSI_STATE_DEAD_SOCKET: + return; + + /* we tried the polite way... */ + case WSI_STATE_AWAITING_CLOSE_ACK: + goto just_kill_connection; + + case WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE: + if (wsi->truncated_send_len) { + libwebsocket_callback_on_writable(context, wsi); + return; + } + lwsl_info("wsi %p completed WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); + goto just_kill_connection; + default: + if (wsi->truncated_send_len) { + lwsl_info("wsi %p entering WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); + wsi->state = WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE; + return; + } + break; + } + + wsi->u.ws.close_reason = reason; + + if (wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT || + wsi->mode == LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE) { + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); + + lws_free_header_table(wsi); + goto just_kill_connection; + } + + if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) { + if (wsi->u.http.fd != LWS_INVALID_FILE) { + lwsl_debug("closing http file\n"); + compatible_file_close(wsi->u.http.fd); + wsi->u.http.fd = LWS_INVALID_FILE; + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0); + } + } + + /* + * are his extensions okay with him closing? Eg he might be a mux + * parent and just his ch1 aspect is closing? + */ + + if (lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, NULL, 0) > 0) { + lwsl_ext("extension vetoed close\n"); + return; + } + + /* + * flush any tx pending from extensions, since we may send close packet + * if there are problems with send, just nuke the connection + */ + + do { + ret = 0; + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* show every extension the new incoming data */ + + m = lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, &eff_buf, 0); + if (m < 0) { + lwsl_ext("Extension reports fatal error\n"); + goto just_kill_connection; + } + if (m) + /* + * at least one extension told us he has more + * to spill, so we will go around again after + */ + ret = 1; + + /* assuming they left us something to send, send it */ + + if (eff_buf.token_len) + if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len) != eff_buf.token_len) { + lwsl_debug("close: ext spill failed\n"); + goto just_kill_connection; + } + } while (ret); + + /* + * signal we are closing, libwebsocket_write will + * add any necessary version-specific stuff. If the write fails, + * no worries we are closing anyway. If we didn't initiate this + * close, then our state has been changed to + * WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this. + * + * Likewise if it's a second call to close this connection after we + * sent the close indication to the peer already, we are in state + * WSI_STATE_AWAITING_CLOSE_ACK and will skip doing this a second time. + */ + + if (old_state == WSI_STATE_ESTABLISHED && + reason != LWS_CLOSE_STATUS_NOSTATUS) { + + lwsl_debug("sending close indication...\n"); + + /* make valgrind happy */ + memset(buf, 0, sizeof(buf)); + n = libwebsocket_write(wsi, + &buf[LWS_SEND_BUFFER_PRE_PADDING + 2], + 0, LWS_WRITE_CLOSE); + if (n >= 0) { + /* + * we have sent a nice protocol level indication we + * now wish to close, we should not send anything more + */ + + wsi->state = WSI_STATE_AWAITING_CLOSE_ACK; + + /* + * ...and we should wait for a reply for a bit + * out of politeness + */ + + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_CLOSE_ACK, 1); + + lwsl_debug("sent close indication, awaiting ack\n"); + + return; + } + + lwsl_info("close: sending close packet failed, hanging up\n"); + + /* else, the send failed and we should just hang up */ + } + +just_kill_connection: + + lwsl_debug("close: just_kill_connection\n"); + + /* + * we won't be servicing or receiving anything further from this guy + * delete socket from the internal poll list if still present + */ + + remove_wsi_socket_from_fds(context, wsi); + + wsi->state = WSI_STATE_DEAD_SOCKET; + + lws_free2(wsi->rxflow_buffer); + + if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING && wsi->u.hdr.ah) { + lws_free2(wsi->u.hdr.ah); + } + + if ((old_state == WSI_STATE_ESTABLISHED || + wsi->mode == LWS_CONNMODE_WS_SERVING || + wsi->mode == LWS_CONNMODE_WS_CLIENT)) { + + lws_free2(wsi->u.ws.rx_user_buffer); + + if (wsi->truncated_send_malloc) { + /* not going to be completed... nuke it */ + lws_free2(wsi->truncated_send_malloc); + wsi->truncated_send_len = 0; + } + if (wsi->u.ws.ping_payload_buf) { + lws_free2(wsi->u.ws.ping_payload_buf); + wsi->u.ws.ping_payload_alloc = 0; + wsi->u.ws.ping_payload_len = 0; + } + } + + /* tell the user it's all over for this guy */ + + if (wsi->protocol && wsi->protocol->callback && + ((old_state == WSI_STATE_ESTABLISHED) || + (old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) || + (old_state == WSI_STATE_AWAITING_CLOSE_ACK) || + (old_state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE))) { + lwsl_debug("calling back CLOSED\n"); + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED, + wsi->user_space, NULL, 0); + } else if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) { + lwsl_debug("calling back CLOSED_HTTP\n"); + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0 ); + } else + lwsl_debug("not calling back closed\n"); + + /* deallocate any active extension contexts */ + + if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_DESTROY, NULL, 0) < 0) + lwsl_warn("extension destruction failed\n"); +#ifndef LWS_NO_EXTENSIONS + for (n = 0; n < wsi->count_active_extensions; n++) + lws_free(wsi->active_extensions_user[n]); +#endif + /* + * inform all extensions in case they tracked this guy out of band + * even though not active on him specifically + */ + if (lws_ext_callback_for_each_extension_type(context, wsi, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, NULL, 0) < 0) + lwsl_warn("ext destroy wsi failed\n"); + +/* lwsl_info("closing fd=%d\n", wsi->sock); */ + + if (!lws_ssl_close(wsi) && wsi->sock >= 0) { + n = shutdown(wsi->sock, SHUT_RDWR); + if (n) + lwsl_debug("closing: shutdown ret %d\n", LWS_ERRNO); + + n = compatible_close(wsi->sock); + if (n) + lwsl_debug("closing: close ret %d\n", LWS_ERRNO); + } + + /* outermost destroy notification for wsi (user_space still intact) */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_WSI_DESTROY, wsi->user_space, NULL, 0); + + if (wsi->protocol && wsi->protocol->per_session_data_size && + wsi->user_space && !wsi->user_space_externally_allocated) + lws_free(wsi->user_space); + + /* As a precaution, free the header table in case it lingered: */ + lws_free_header_table(wsi); + lws_free(wsi); +} + +/** + * libwebsockets_get_peer_addresses() - Get client address information + * @context: Libwebsockets context + * @wsi: Local struct libwebsocket associated with + * @fd: Connection socket descriptor + * @name: Buffer to take client address name + * @name_len: Length of client address name buffer + * @rip: Buffer to take client address IP dotted quad + * @rip_len: Length of client address IP buffer + * + * This function fills in @name and @rip with the name and IP of + * the client connected with socket descriptor @fd. Names may be + * truncated if there is not enough room. If either cannot be + * determined, they will be returned as valid zero-length strings. + */ + +LWS_VISIBLE void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len) +{ + socklen_t len; +#ifdef LWS_USE_IPV6 + struct sockaddr_in6 sin6; +#endif + struct sockaddr_in sin4; + struct hostent *host; + struct hostent *host1; + char ip[128]; + unsigned char *p; + int n; +#ifdef AF_LOCAL + struct sockaddr_un *un; +#endif + int ret = -1; + + rip[0] = '\0'; + name[0] = '\0'; + + lws_latency_pre(context, wsi); + +#ifdef LWS_USE_IPV6 + if (LWS_IPV6_ENABLED(context)) { + + len = sizeof(sin6); + if (getpeername(fd, (struct sockaddr *) &sin6, &len) < 0) { + lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); + goto bail; + } + + if (!lws_plat_inet_ntop(AF_INET6, &sin6.sin6_addr, rip, rip_len)) { + lwsl_err("inet_ntop", strerror(LWS_ERRNO)); + goto bail; + } + + // Strip off the IPv4 to IPv6 header if one exists + if (strncmp(rip, "::ffff:", 7) == 0) + memmove(rip, rip + 7, strlen(rip) - 6); + + getnameinfo((struct sockaddr *)&sin6, + sizeof(struct sockaddr_in6), name, + name_len, NULL, 0, 0); + + } else +#endif + { + len = sizeof(sin4); + if (getpeername(fd, (struct sockaddr *) &sin4, &len) < 0) { + lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); + goto bail; + } + host = gethostbyaddr((char *) &sin4.sin_addr, + sizeof(sin4.sin_addr), AF_INET); + if (host == NULL) { + lwsl_warn("gethostbyaddr: %s\n", strerror(LWS_ERRNO)); + goto bail; + } + + strncpy(name, host->h_name, name_len); + name[name_len - 1] = '\0'; + + host1 = gethostbyname(host->h_name); + if (host1 == NULL) + goto bail; + p = (unsigned char *)host1; + n = 0; + while (p != NULL) { + p = (unsigned char *)host1->h_addr_list[n++]; + if (p == NULL) + continue; + if ((host1->h_addrtype != AF_INET) +#ifdef AF_LOCAL + && (host1->h_addrtype != AF_LOCAL) +#endif + ) + continue; + + if (host1->h_addrtype == AF_INET) + sprintf(ip, "%u.%u.%u.%u", + p[0], p[1], p[2], p[3]); +#ifdef AF_LOCAL + else { + un = (struct sockaddr_un *)p; + strncpy(ip, un->sun_path, sizeof(ip) - 1); + ip[sizeof(ip) - 1] = '\0'; + } +#endif + p = NULL; + strncpy(rip, ip, rip_len); + rip[rip_len - 1] = '\0'; + } + } + + ret = 0; +bail: + lws_latency(context, wsi, "libwebsockets_get_peer_addresses", ret, 1); +} + + + +/** + * libwebsocket_context_user() - get the user data associated with the context + * @context: Websocket context + * + * This returns the optional user allocation that can be attached to + * the context the sockets live in at context_create time. It's a way + * to let all sockets serviced in the same context share data without + * using globals statics in the user code. + */ +LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context) +{ + return context->user_space; +} + + +/** + * libwebsocket_callback_all_protocol() - Callback all connections using + * the given protocol with the given reason + * + * @protocol: Protocol whose connections will get callbacks + * @reason: Callback reason index + */ + +LWS_VISIBLE int +libwebsocket_callback_all_protocol( + const struct libwebsocket_protocols *protocol, int reason) +{ + struct libwebsocket_context *context = protocol->owning_server; + int n; + struct libwebsocket *wsi; + + for (n = 0; n < context->fds_count; n++) { + wsi = context->lws_lookup[context->fds[n].fd]; + if (!wsi) + continue; + if (wsi->protocol == protocol) + protocol->callback(context, wsi, + reason, wsi->user_space, NULL, 0); + } + + return 0; +} + +/** + * libwebsocket_set_timeout() - marks the wsi as subject to a timeout + * + * You will not need this unless you are doing something special + * + * @wsi: Websocket connection instance + * @reason: timeout reason + * @secs: how many seconds + */ + +LWS_VISIBLE void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs) +{ + time_t now; + + time(&now); + + wsi->pending_timeout_limit = now + secs; + wsi->pending_timeout = reason; +} + + +/** + * libwebsocket_get_socket_fd() - returns the socket file descriptor + * + * You will not need this unless you are doing something special + * + * @wsi: Websocket connection instance + */ + +LWS_VISIBLE int +libwebsocket_get_socket_fd(struct libwebsocket *wsi) +{ + return wsi->sock; +} + +#ifdef LWS_LATENCY +void +lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, + const char *action, int ret, int completed) +{ + unsigned long long u; + char buf[256]; + + u = time_in_microseconds(); + + if (!action) { + wsi->latency_start = u; + if (!wsi->action_start) + wsi->action_start = u; + return; + } + if (completed) { + if (wsi->action_start == wsi->latency_start) + sprintf(buf, + "Completion first try lat %lluus: %p: ret %d: %s\n", + u - wsi->latency_start, + (void *)wsi, ret, action); + else + sprintf(buf, + "Completion %lluus: lat %lluus: %p: ret %d: %s\n", + u - wsi->action_start, + u - wsi->latency_start, + (void *)wsi, ret, action); + wsi->action_start = 0; + } else + sprintf(buf, "lat %lluus: %p: ret %d: %s\n", + u - wsi->latency_start, (void *)wsi, ret, action); + + if (u - wsi->latency_start > context->worst_latency) { + context->worst_latency = u - wsi->latency_start; + strcpy(context->worst_latency_info, buf); + } + lwsl_latency("%s", buf); +} +#endif + + + +/** + * libwebsocket_rx_flow_control() - Enable and disable socket servicing for + * received packets. + * + * If the output side of a server process becomes choked, this allows flow + * control for the input side. + * + * @wsi: Websocket connection instance to get callback for + * @enable: 0 = disable read servicing for this connection, 1 = enable + */ + +LWS_VISIBLE int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable) +{ + if (enable == (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) + return 0; + + lwsl_info("libwebsocket_rx_flow_control(0x%p, %d)\n", wsi, enable); + wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !!enable; + + return 0; +} + +/** + * libwebsocket_rx_flow_allow_all_protocol() - Allow all connections with this protocol to receive + * + * When the user server code realizes it can accept more input, it can + * call this to have the RX flow restriction removed from all connections using + * the given protocol. + * + * @protocol: all connections using this protocol will be allowed to receive + */ + +LWS_VISIBLE void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol) +{ + struct libwebsocket_context *context = protocol->owning_server; + int n; + struct libwebsocket *wsi; + + for (n = 0; n < context->fds_count; n++) { + wsi = context->lws_lookup[context->fds[n].fd]; + if (!wsi) + continue; + if (wsi->protocol == protocol) + libwebsocket_rx_flow_control(wsi, LWS_RXFLOW_ALLOW); + } +} + + +/** + * libwebsocket_canonical_hostname() - returns this host's hostname + * + * This is typically used by client code to fill in the host parameter + * when making a client connection. You can only call it after the context + * has been created. + * + * @context: Websocket context + */ +LWS_VISIBLE extern const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context) +{ + return (const char *)context->canonical_hostname; +} + +int user_callback_handle_rxflow(callback_function callback_function, + struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len) +{ + int n; + + n = callback_function(context, wsi, reason, user, in, len); + if (!n) + n = _libwebsocket_rx_flow_control(wsi); + + return n; +} + + +/** + * libwebsocket_set_proxy() - Setups proxy to libwebsocket_context. + * @context: pointer to struct libwebsocket_context you want set proxy to + * @proxy: pointer to c string containing proxy in format address:port + * + * Returns 0 if proxy string was parsed and proxy was setup. + * Returns -1 if @proxy is NULL or has incorrect format. + * + * This is only required if your OS does not provide the http_proxy + * environment variable (eg, OSX) + * + * IMPORTANT! You should call this function right after creation of the + * libwebsocket_context and before call to connect. If you call this + * function after connect behavior is undefined. + * This function will override proxy settings made on libwebsocket_context + * creation with genenv() call. + */ + +LWS_VISIBLE int +libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy) +{ + char *p; + + if (!proxy) + return -1; + + strncpy(context->http_proxy_address, proxy, + sizeof(context->http_proxy_address) - 1); + context->http_proxy_address[ + sizeof(context->http_proxy_address) - 1] = '\0'; + + p = strchr(context->http_proxy_address, ':'); + if (!p) { + lwsl_err("http_proxy needs to be ads:port\n"); + + return -1; + } + *p = '\0'; + context->http_proxy_port = atoi(p + 1); + + lwsl_notice(" Proxy %s:%u\n", context->http_proxy_address, + context->http_proxy_port); + + return 0; +} + +/** + * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket + * connection. + * @wsi: pointer to struct websocket you want to know the protocol of + * + * + * Some apis can act on all live connections of a given protocol, + * this is how you can get a pointer to the active protocol if needed. + */ + +LWS_VISIBLE const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi) +{ + return wsi->protocol; +} + +LWS_VISIBLE int +libwebsocket_is_final_fragment(struct libwebsocket *wsi) +{ + return wsi->u.ws.final; +} + +LWS_VISIBLE unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi) +{ + return wsi->u.ws.rsv; +} + +int +libwebsocket_ensure_user_space(struct libwebsocket *wsi) +{ + lwsl_info("%s: %p protocol %p\n", __func__, wsi, wsi->protocol); + if (!wsi->protocol) + return 1; + + /* allocate the per-connection user memory (if any) */ + + if (wsi->protocol->per_session_data_size && !wsi->user_space) { + wsi->user_space = lws_zalloc(wsi->protocol->per_session_data_size); + if (wsi->user_space == NULL) { + lwsl_err("Out of memory for conn user space\n"); + return 1; + } + } else + lwsl_info("%s: %p protocol pss %u, user_space=%d\n", __func__, wsi, wsi->protocol->per_session_data_size, wsi->user_space); + return 0; +} + +LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line) +{ + char buf[300]; + unsigned long long now; + int n; + + buf[0] = '\0'; + for (n = 0; n < LLL_COUNT; n++) + if (level == (1 << n)) { + now = time_in_microseconds() / 100; + sprintf(buf, "[%lu:%04d] %s: ", (unsigned long) now / 10000, + (int)(now % 10000), log_level_names[n]); + break; + } + + fprintf(stderr, "%s%s", buf, line); +} + + +LWS_VISIBLE void _lws_logv(int filter, const char *format, va_list vl) +{ + char buf[256]; + + if (!(log_level & filter)) + return; + + vsnprintf(buf, sizeof(buf), format, vl); + buf[sizeof(buf) - 1] = '\0'; + + lwsl_emit(filter, buf); +} + +LWS_VISIBLE void _lws_log(int filter, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + _lws_logv(filter, format, ap); + va_end(ap); +} + +/** + * lws_set_log_level() - Set the logging bitfield + * @level: OR together the LLL_ debug contexts you want output from + * @log_emit_function: NULL to leave it as it is, or a user-supplied + * function to perform log string emission instead of + * the default stderr one. + * + * log level defaults to "err", "warn" and "notice" contexts enabled and + * emission on stderr. + */ + +LWS_VISIBLE void lws_set_log_level(int level, void (*log_emit_function)(int level, + const char *line)) +{ + log_level = level; + if (log_emit_function) + lwsl_emit = log_emit_function; +} + +/** + * lws_use_ssl() - Find out if connection is using SSL + * @wsi: websocket connection to check + * + * Returns 0 if the connection is not using SSL, 1 if using SSL and + * using verified cert, and 2 if using SSL but the cert was not + * checked (appears for client wsi told to skip check on connection) + */ +LWS_VISIBLE int +lws_is_ssl(struct libwebsocket *wsi) +{ +#ifdef LWS_OPENSSL_SUPPORT + return wsi->use_ssl; +#else + return 0; +#endif +} + +/** + * lws_partial_buffered() - find out if lws buffered the last write + * @wsi: websocket connection to check + * + * Returns 1 if you cannot use libwebsocket_write because the last + * write on this connection is still buffered, and can't be cleared without + * returning to the service loop and waiting for the connection to be + * writeable again. + * + * If you will try to do >1 libwebsocket_write call inside a single + * WRITEABLE callback, you must check this after every write and bail if + * set, ask for a new writeable callback and continue writing from there. + * + * This is never set at the start of a writeable callback, but any write + * may set it. + */ + +LWS_VISIBLE int +lws_partial_buffered(struct libwebsocket *wsi) +{ + return !!wsi->truncated_send_len; +} + +void lws_set_protocol_write_pending(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum lws_pending_protocol_send pend) +{ + lwsl_info("setting pps %d\n", pend); + + if (wsi->pps) + lwsl_err("pps overwrite\n"); + wsi->pps = pend; + libwebsocket_rx_flow_control(wsi, 0); + libwebsocket_callback_on_writable(context, wsi); +} + +LWS_VISIBLE size_t +lws_get_peer_write_allowance(struct libwebsocket *wsi) +{ +#ifdef LWS_USE_HTTP2 + /* only if we are using HTTP2 on this connection */ + if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) + return -1; + /* user is only interested in how much he can send, or that he can't */ + if (wsi->u.http2.tx_credit <= 0) + return 0; + + return wsi->u.http2.tx_credit; +#else + return -1; +#endif +} + +LWS_VISIBLE void +lws_union_transition(struct libwebsocket *wsi, enum connection_mode mode) +{ + memset(&wsi->u, 0, sizeof(wsi->u)); + wsi->mode = mode; +} diff --git a/src/engine/external/libwebsockets/libwebsockets.h b/src/engine/external/libwebsockets/libwebsockets.h new file mode 100644 index 00000000..3c717ff4 --- /dev/null +++ b/src/engine/external/libwebsockets/libwebsockets.h @@ -0,0 +1,1371 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C +#define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C + +#ifdef __cplusplus +#include <cstddef> +#include <cstdarg> +extern "C" { +#endif + +#ifdef CMAKE_BUILD +#include "lws_config.h" +#endif + +#if defined(WIN32) || defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <winsock2.h> +#include <ws2tcpip.h> +#include <stddef.h> +#include <stdint.h> +#include <basetsd.h> + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 + +#include <poll.h> +#include <unistd.h> + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#ifdef LWS_USE_LIBEV +#include <ev.h> +#endif /* LWS_USE_LIBEV */ + +#include <assert.h> + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#ifdef _WIN32 +#define random rand +#else +#include <sys/time.h> +#include <unistd.h> +#endif + +#ifdef LWS_OPENSSL_SUPPORT +#ifdef USE_CYASSL +#include <cyassl/openssl/ssl.h> +#else +#include <openssl/ssl.h> +#endif /* not USE_CYASSL */ +#endif + +#define CONTEXT_PORT_NO_LISTEN -1 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); +LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* api change list for user code to test against */ + +#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG + +/* the struct libwebsocket_protocols has the id field present */ +#define LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD + +/* you can call lws_get_peer_write_allowance */ +#define LWS_FEATURE_PROTOCOLS_HAS_PEER_WRITE_ALLOWANCE + +/* extra parameter introduced in 917f43ab821 */ +#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_LEN + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, + LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8, + LWS_SERVER_OPTION_LIBEV = 16, + LWS_SERVER_OPTION_DISABLE_IPV6 = 32, + LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS = 64, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_CLOSED_HTTP, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_BODY, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + LWS_CALLBACK_WSI_CREATE, /* always protocol[0] */ + LWS_CALLBACK_WSI_DESTROY, /* always protocol[0] */ + LWS_CALLBACK_GET_THREAD_ID, + + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_CHANGE_MODE_POLL_FD, + LWS_CALLBACK_LOCK_POLL, + LWS_CALLBACK_UNLOCK_POLL, + + LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, + + LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ +}; + +// argument structure for all external poll related calls +// passed in via 'in' +struct libwebsocket_pollargs { + int fd; // applicable file descriptor + int events; // the new event mask + int prev_events; // the previous event mask +}; + +#ifdef _WIN32 +struct libwebsocket_pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +}; +#else +#define libwebsocket_pollfd pollfd +#endif + +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* Same as write_http but we know this write ends the transaction */ + LWS_WRITE_HTTP_FINAL, + + /* HTTP2 */ + + LWS_WRITE_HTTP_HEADERS, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +/* + * don't forget to update test server header dump accordingly + * + * these have to be kept in sync with lextable.h / minilex.c + */ + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_POST_URI, + WSI_TOKEN_OPTIONS_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + WSI_TOKEN_EXTENSIONS, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + WSI_TOKEN_HTTP2_SETTINGS, + WSI_TOKEN_HTTP_ACCEPT, + WSI_TOKEN_HTTP_AC_REQUEST_HEADERS, + WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, + WSI_TOKEN_HTTP_IF_NONE_MATCH, + WSI_TOKEN_HTTP_ACCEPT_ENCODING, + WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, + WSI_TOKEN_HTTP_PRAGMA, + WSI_TOKEN_HTTP_CACHE_CONTROL, + WSI_TOKEN_HTTP_AUTHORIZATION, + WSI_TOKEN_HTTP_COOKIE, + WSI_TOKEN_HTTP_CONTENT_LENGTH, + WSI_TOKEN_HTTP_CONTENT_TYPE, + WSI_TOKEN_HTTP_DATE, + WSI_TOKEN_HTTP_RANGE, + WSI_TOKEN_HTTP_REFERER, + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + WSI_TOKEN_HTTP_COLON_AUTHORITY, + WSI_TOKEN_HTTP_COLON_METHOD, + WSI_TOKEN_HTTP_COLON_PATH, + WSI_TOKEN_HTTP_COLON_SCHEME, + WSI_TOKEN_HTTP_COLON_STATUS, + + WSI_TOKEN_HTTP_ACCEPT_CHARSET, + WSI_TOKEN_HTTP_ACCEPT_RANGES, + WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN, + WSI_TOKEN_HTTP_AGE, + WSI_TOKEN_HTTP_ALLOW, + WSI_TOKEN_HTTP_CONTENT_DISPOSITION, + WSI_TOKEN_HTTP_CONTENT_ENCODING, + WSI_TOKEN_HTTP_CONTENT_LANGUAGE, + WSI_TOKEN_HTTP_CONTENT_LOCATION, + WSI_TOKEN_HTTP_CONTENT_RANGE, + WSI_TOKEN_HTTP_ETAG, + WSI_TOKEN_HTTP_EXPECT, + WSI_TOKEN_HTTP_EXPIRES, + WSI_TOKEN_HTTP_FROM, + WSI_TOKEN_HTTP_IF_MATCH, + WSI_TOKEN_HTTP_IF_RANGE, + WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE, + WSI_TOKEN_HTTP_LAST_MODIFIED, + WSI_TOKEN_HTTP_LINK, + WSI_TOKEN_HTTP_LOCATION, + WSI_TOKEN_HTTP_MAX_FORWARDS, + WSI_TOKEN_HTTP_PROXY_AUTHENTICATE, + WSI_TOKEN_HTTP_PROXY_AUTHORIZATION, + WSI_TOKEN_HTTP_REFRESH, + WSI_TOKEN_HTTP_RETRY_AFTER, + WSI_TOKEN_HTTP_SERVER, + WSI_TOKEN_HTTP_SET_COOKIE, + WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY, + WSI_TOKEN_HTTP_TRANSFER_ENCODING, + WSI_TOKEN_HTTP_USER_AGENT, + WSI_TOKEN_HTTP_VARY, + WSI_TOKEN_HTTP_VIA, + WSI_TOKEN_HTTP_WWW_AUTHENTICATE, + WSI_TOKEN_PROXY, + + WSI_TOKEN_HTTP_URI_ARGS, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +struct lws_token_limits { + unsigned short token_limit[WSI_TOKEN_COUNT]; +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +enum http_status { + HTTP_STATUS_OK = 200, + HTTP_STATUS_NO_CONTENT = 204, + + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED, + HTTP_STATUS_PAYMENT_REQUIRED, + HTTP_STATUS_FORBIDDEN, + HTTP_STATUS_NOT_FOUND, + HTTP_STATUS_METHOD_NOT_ALLOWED, + HTTP_STATUS_NOT_ACCEPTABLE, + HTTP_STATUS_PROXY_AUTH_REQUIRED, + HTTP_STATUS_REQUEST_TIMEOUT, + HTTP_STATUS_CONFLICT, + HTTP_STATUS_GONE, + HTTP_STATUS_LENGTH_REQUIRED, + HTTP_STATUS_PRECONDITION_FAILED, + HTTP_STATUS_REQ_ENTITY_TOO_LARGE, + HTTP_STATUS_REQ_URI_TOO_LONG, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, + HTTP_STATUS_EXPECTATION_FAILED, + + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED, + HTTP_STATUS_BAD_GATEWAY, + HTTP_STATUS_SERVICE_UNAVAILABLE, + HTTP_STATUS_GATEWAY_TIMEOUT, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @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 the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_CLOSED_HTTP: when a HTTP (non-websocket) session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, 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. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_BODY: the next @len bytes data from the http + * request body HTTP connection is now available in @in. + * + * LWS_CALLBACK_HTTP_BODY_COMPLETION: the expected amount of http request + * body has been delivered + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Since the client connection information is + * not available yet, @wsi still pointing to the main server socket. + * Return non-zero to terminate the connection before sending or + * receiving anything. Because this happens immediately after the + * network connection from the client, there's no websocket protocol + * selected yet so this callback is issued only to protocol 0. + * + * LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: A new client just had + * been connected, accepted, and instantiated into the pool. This + * callback allows setting any relevant property to it. Because this + * happens immediately after the instantiation of a new client, + * there's no websocket protocol selected yet so this callback is + * issued only to protocol 0. Only @wsi is defined, pointing to the + * new client, and the return value is ignored. + * + * LWS_CALLBACK_FILTER_HTTP_CONNECTION: called when the request has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the URI, eg, "/" + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the http + * connection to proceed or to kill the connection. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the requested protocol name + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the handshake + * to proceed or to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY: if configured for + * including OpenSSL support but no private key file has been specified + * (ssl_private_key_filepath is NULL), this callback is called to + * allow the user to set the private key directly via libopenssl + * and perform further operations if required; this might be useful + * in situations where the private key is not directly accessible by + * the OS, for example if it is stored on a smartcard + * @user is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * LWS_CALLBACK_WSI_CREATE: outermost (earliest) wsi create notification + * + * LWS_CALLBACK_WSI_DESTROY: outermost (latest) wsi destroy notification + * + * The next five reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * For these calls, @in points to a struct libwebsocket_pollargs that + * contains @fd, @events and @prev_events members + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. + * This callback happens when a socket needs to be + * added to the polling loop: @in points to a struct + * libwebsocket_pollargs; the @fd member of the struct is the file + * descriptor, and @events contains the active events. + * + * If you are using the internal polling loop (the "service" + * callback), you can just ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * again the struct libwebsocket_pollargs containing the @fd member + * to be removed. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_CHANGE_MODE_POLL_FD: This callback happens when + * libwebsockets wants to modify the events for a connectiion. + * @in is the struct libwebsocket_pollargs with the @fd to change. + * The new event mask is in @events member and the old mask is in + * the @prev_events member. + * If you are using the internal polling loop, you can just ignore + * it. + * + * LWS_CALLBACK_LOCK_POLL: + * LWS_CALLBACK_UNLOCK_POLL: These allow the external poll changes driven + * by libwebsockets to participate in an external thread locking + * scheme around the changes, so the whole thing is threadsafe. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @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 + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * 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 + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @id: ignored by lws, but useful to contain user information bound + * to the selected protocol. For example if this protocol was + * called "myprotocol-v2", you might set id to 2, and the user + * code that acts differently according to the version can do so by + * switch (wsi->protocol->id), user code might use some bits as + * capability flags based on selected protocol version, etc. + * @user: User provided context data at the protocol level. + * Accessible via libwebsockets_get_protocol(wsi)->user + * This should not be confused with wsi->user, it is not the same. + * The library completely ignores any value in here. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * 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. + * + * The first protocol given has its callback used for user callbacks when + * there is no agreed protocol name, that's true during HTTP part of the + * connection and true if the client did not send a Protocol: header. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + unsigned int id; + void *user; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use CONTEXT_PORT_NO_LISTEN to + * suppress listening on any port, that's what you want if you are + * not running a websocket server at all but just using it as a + * client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @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. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @token_limits: NULL or struct lws_token_limits pointer which is initialized + * with a token length limit for each possible WSI_TOKEN_*** + * @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 + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode; + * if this is set to NULL but sll_cert_filepath is set, the + * OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY callback is called to allow + * setting of the private key directly via openSSL library calls + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + * @provided_client_ssl_ctx: If non-null, swap out libwebsockets ssl + * implementation for the one provided by provided_ssl_ctx. + * Libwebsockets no longer is responsible for freeing the context + * if this option is selected. + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + struct lws_token_limits *token_limits; + const char *ssl_private_key_password; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + const char *http_proxy_address; + unsigned int http_proxy_port; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; +#ifdef LWS_OPENSSL_SUPPORT + SSL_CTX *provided_client_ssl_ctx; +#else /* maintain structure layout either way */ + void *provided_client_ssl_ctx; +#endif +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_cancel_service(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN const unsigned char * +lws_token_to_string(enum lws_token_indexes token); + +LWS_VISIBLE LWS_EXTERN int +lws_add_http_header_by_name(struct libwebsocket_context *context, + struct libwebsocket *wsi, + const unsigned char *name, + const unsigned char *value, + int length, + unsigned char **p, + unsigned char *end); +LWS_VISIBLE LWS_EXTERN int +lws_finalize_http_header(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char **p, + unsigned char *end); +LWS_VISIBLE LWS_EXTERN int +lws_add_http_header_by_token(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum lws_token_indexes token, + const unsigned char *value, + int length, + unsigned char **p, + unsigned char *end); +LWS_VISIBLE LWS_EXTERN int lws_add_http_header_content_length(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned long content_length, + unsigned char **p, + unsigned char *end); +LWS_VISIBLE LWS_EXTERN int +lws_add_http_header_status(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned int code, + unsigned char **p, + unsigned char *end); + +LWS_EXTERN int lws_http_transaction_completed(struct libwebsocket *wsi); + +#ifdef LWS_USE_LIBEV +LWS_VISIBLE LWS_EXTERN int +libwebsocket_initloop( + struct libwebsocket_context *context, struct ev_loop *loop); + +LWS_VISIBLE void +libwebsocket_sigint_cb( + struct ev_loop *loop, struct ev_signal *watcher, int revents); +#endif /* LWS_USE_LIBEV */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct libwebsocket_pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +enum pending_timeout { + NO_PENDING_TIMEOUT = 0, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, + PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, + PENDING_TIMEOUT_AWAITING_PING, + PENDING_TIMEOUT_CLOSE_ACK, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, + PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, + PENDING_TIMEOUT_SSL_ACCEPT, + PENDING_TIMEOUT_HTTP_CONTENT, + PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, +}; + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * 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]; + * + * // 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, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +/* helper for case where buffer may be const */ +#define libwebsocket_write_http(wsi, buf, len) \ + libwebsocket_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP) + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type, const char *other_headers, + int other_headers_len); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int libwebsockets_return_http_status( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int code, + const char *html_body); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_all_protocol( + const struct libwebsocket_protocols *protocol, int reason); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +/* + * if the protocol does not have any guidence, returns -1. Currently only + * http2 connections get send window information from this API. But your code + * should use it so it can work properly with any protocol. + * + * If nonzero return is the amount of payload data the peer or intermediary has + * reported it has buffer space for. That has NO relationship with the amount + * of buffer space your OS can accept on this connection for a write action. + * + * This number represents the maximum you could send to the peer or intermediary + * on this connection right now without it complaining. + * + * lws manages accounting for send window updates and payload writes + * automatically, so this number reflects the situation at the peer or + * intermediary dynamically. + */ +LWS_VISIBLE LWS_EXTERN size_t +lws_get_peer_write_allowance(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_partial_buffered(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_is_ssl(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +/* + * custom allocator support + */ +LWS_VISIBLE LWS_EXTERN void +lws_set_allocator(void *(*realloc)(void *ptr, size_t size)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/engine/external/libwebsockets/lws-plat-unix.c b/src/engine/external/libwebsockets/lws-plat-unix.c new file mode 100644 index 00000000..9af4bdfd --- /dev/null +++ b/src/engine/external/libwebsockets/lws-plat-unix.c @@ -0,0 +1,442 @@ +#include "private-libwebsockets.h" + +/* + * included from libwebsockets.c for unix builds + */ + +unsigned long long time_in_microseconds(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000000) + tv.tv_usec; +} + +LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len) +{ + return read(context->fd_random, (char *)buf, len); +} + +LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi) +{ + struct libwebsocket_pollfd fds; + + /* treat the fact we got a truncated send pending as if we're choked */ + if (wsi->truncated_send_len) + return 1; + + fds.fd = wsi->sock; + fds.events = POLLOUT; + fds.revents = 0; + + if (poll(&fds, 1, 0) != 1) + return 1; + + if ((fds.revents & POLLOUT) == 0) + return 1; + + /* okay to send another packet without blocking */ + + return 0; +} + +LWS_VISIBLE int +lws_poll_listen_fd(struct libwebsocket_pollfd *fd) +{ + return poll(fd, 1, 0); +} + +/* + * This is just used to interrupt poll waiting + * we don't have to do anything with it. + */ +static void lws_sigusr2(int sig) +{ +} + +/** + * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity + * @context: Websocket context + * + * This function let a call to libwebsocket_service() waiting for a timeout + * immediately return. + */ +LWS_VISIBLE void +libwebsocket_cancel_service(struct libwebsocket_context *context) +{ + char buf = 0; + + if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1) + lwsl_err("Cannot write to dummy pipe"); +} + +LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) +{ + int syslog_level = LOG_DEBUG; + + switch (level) { + case LLL_ERR: + syslog_level = LOG_ERR; + break; + case LLL_WARN: + syslog_level = LOG_WARNING; + break; + case LLL_NOTICE: + syslog_level = LOG_NOTICE; + break; + case LLL_INFO: + syslog_level = LOG_INFO; + break; + } + syslog(syslog_level, "%s", line); +} + +LWS_VISIBLE int +lws_plat_service(struct libwebsocket_context *context, int timeout_ms) +{ + int n; + int m; + char buf; + + /* stay dead once we are dead */ + + if (!context) + return 1; + + lws_libev_run(context); + + context->service_tid = context->protocols[0].callback(context, NULL, + LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); + +#ifdef LWS_OPENSSL_SUPPORT + /* if we know we have non-network pending data, do not wait in poll */ + if (context->ssl_flag_buffered_reads) + timeout_ms = 0; +#endif + n = poll(context->fds, context->fds_count, timeout_ms); + context->service_tid = 0; + +#ifdef LWS_OPENSSL_SUPPORT + if (!context->ssl_flag_buffered_reads && n == 0) { +#else + if (n == 0) /* poll timeout */ { +#endif + libwebsocket_service_fd(context, NULL); + return 0; + } + +#ifdef LWS_OPENSSL_SUPPORT + /* any more will have to set it fresh this time around */ + context->ssl_flag_buffered_reads = 0; +#endif + + if (n < 0) { + if (LWS_ERRNO != LWS_EINTR) + return -1; + return 0; + } + + /* any socket with events to service? */ + + for (n = 0; n < context->fds_count; n++) { +#ifdef LWS_OPENSSL_SUPPORT + struct libwebsocket *wsi; + + wsi = context->lws_lookup[context->fds[n].fd]; + if (wsi == NULL) + continue; + /* + * if he's not flowcontrolled, make sure we service ssl + * pending read data + */ + if (wsi->ssl && wsi->buffered_reads_pending) { + lwsl_debug("wsi %p: forcing POLLIN\n", wsi); + context->fds[n].revents |= context->fds[n].events & POLLIN; + if (context->fds[n].revents & POLLIN) + wsi->buffered_reads_pending = 0; + else + /* somebody left with pending SSL read data */ + context->ssl_flag_buffered_reads = 1; + } +#endif + if (!context->fds[n].revents) + continue; + + if (context->fds[n].fd == context->dummy_pipe_fds[0]) { + if (read(context->fds[n].fd, &buf, 1) != 1) + lwsl_err("Cannot read from dummy pipe."); + continue; + } + + m = libwebsocket_service_fd(context, &context->fds[n]); + if (m < 0) + return -1; + /* if something closed, retry this slot */ + if (m) + n--; + } + + return 0; +} + +LWS_VISIBLE int +lws_plat_set_socket_options(struct libwebsocket_context *context, int fd) +{ + int optval = 1; + socklen_t optlen = sizeof(optval); + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__OpenBSD__) + struct protoent *tcp_proto; +#endif + + if (context->ka_time) { + /* enable keepalive on this socket */ + optval = 1; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (const void *)&optval, optlen) < 0) + return 1; + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__CYGWIN__) || defined(__OpenBSD__) + + /* + * didn't find a way to set these per-socket, need to + * tune kernel systemwide values + */ +#else + /* set the keepalive conditions we want on it too */ + optval = context->ka_time; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, + (const void *)&optval, optlen) < 0) + return 1; + + optval = context->ka_interval; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, + (const void *)&optval, optlen) < 0) + return 1; + + optval = context->ka_probes; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, + (const void *)&optval, optlen) < 0) + return 1; +#endif + } + + /* Disable Nagle */ + optval = 1; +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ + !defined(__OpenBSD__) + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) + return 1; +#else + tcp_proto = getprotobyname("TCP"); + if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0) + return 1; +#endif + + /* We are nonblocking... */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + return 1; + + return 0; +} + +LWS_VISIBLE void +lws_plat_drop_app_privileges(struct lws_context_creation_info *info) +{ + if (info->gid != -1) + if (setgid(info->gid)) + lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO)); + if (info->uid != -1) + if (setuid(info->uid)) + lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO)); +} + +LWS_VISIBLE int +lws_plat_init_fd_tables(struct libwebsocket_context *context) +{ + if (lws_libev_init_fd_table(context)) + /* libev handled it instead */ + return 0; + + if (pipe(context->dummy_pipe_fds)) { + lwsl_err("Unable to create pipe\n"); + return 1; + } + + /* use the read end of pipe as first item */ + context->fds[0].fd = context->dummy_pipe_fds[0]; + context->fds[0].events = LWS_POLLIN; + context->fds[0].revents = 0; + context->fds_count = 1; + + context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); + if (context->fd_random < 0) { + lwsl_err("Unable to open random device %s %d\n", + SYSTEM_RANDOM_FILEPATH, context->fd_random); + return 1; + } + + return 0; +} + +static void sigpipe_handler(int x) +{ +} + + +LWS_VISIBLE int +lws_plat_context_early_init(void) +{ + sigset_t mask; + + signal(SIGUSR2, lws_sigusr2); + sigemptyset(&mask); + sigaddset(&mask, SIGUSR2); + + sigprocmask(SIG_BLOCK, &mask, NULL); + + signal(SIGPIPE, sigpipe_handler); + + return 0; +} + +LWS_VISIBLE void +lws_plat_context_early_destroy(struct libwebsocket_context *context) +{ +} + +LWS_VISIBLE void +lws_plat_context_late_destroy(struct libwebsocket_context *context) +{ + close(context->dummy_pipe_fds[0]); + close(context->dummy_pipe_fds[1]); + close(context->fd_random); +} + +/* cast a struct sockaddr_in6 * into addr for ipv6 */ + +LWS_VISIBLE int +interface_to_sa(struct libwebsocket_context *context, + const char *ifname, struct sockaddr_in *addr, size_t addrlen) +{ + int rc = -1; + + struct ifaddrs *ifr; + struct ifaddrs *ifc; +#ifdef LWS_USE_IPV6 + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; +#endif + + getifaddrs(&ifr); + for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) { + if (!ifc->ifa_addr) + continue; + + lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname); + + if (strcmp(ifc->ifa_name, ifname)) + continue; + + switch (ifc->ifa_addr->sa_family) { + case AF_INET: +#ifdef LWS_USE_IPV6 + if (LWS_IPV6_ENABLED(context)) { + /* map IPv4 to IPv6 */ + bzero((char *)&addr6->sin6_addr, + sizeof(struct in6_addr)); + addr6->sin6_addr.s6_addr[10] = 0xff; + addr6->sin6_addr.s6_addr[11] = 0xff; + memcpy(&addr6->sin6_addr.s6_addr[12], + &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr, + sizeof(struct in_addr)); + } else +#endif + memcpy(addr, + (struct sockaddr_in *)ifc->ifa_addr, + sizeof(struct sockaddr_in)); + break; +#ifdef LWS_USE_IPV6 + case AF_INET6: + memcpy(&addr6->sin6_addr, + &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr, + sizeof(struct in6_addr)); + break; +#endif + default: + continue; + } + rc = 0; + } + + freeifaddrs(ifr); + + if (rc == -1) { + /* check if bind to IP adddress */ +#ifdef LWS_USE_IPV6 + if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) + rc = 0; + else +#endif + if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1) + rc = 0; + } + + return rc; +} + +LWS_VISIBLE void +lws_plat_insert_socket_into_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); + context->fds[context->fds_count++].revents = 0; +} + +LWS_VISIBLE void +lws_plat_delete_socket_from_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi, int m) +{ +} + +LWS_VISIBLE void +lws_plat_service_periodic(struct libwebsocket_context *context) +{ + /* if our parent went down, don't linger around */ + if (context->started_with_parent && + kill(context->started_with_parent, 0) < 0) + kill(getpid(), SIGTERM); +} + +LWS_VISIBLE int +lws_plat_change_pollfd(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd) +{ + return 0; +} + +LWS_VISIBLE int +lws_plat_open_file(const char* filename, unsigned long* filelen) +{ + struct stat stat_buf; + int ret = open(filename, O_RDONLY); + + if (ret < 0) + return LWS_INVALID_FILE; + + if (fstat(ret, &stat_buf) < 0) { + close(ret); + return LWS_INVALID_FILE; + } + *filelen = stat_buf.st_size; + return ret; +} + +#ifdef LWS_USE_IPV6 +LWS_VISIBLE const char * +lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) +{ + return inet_ntop(af, src, dst, cnt); +} +#endif diff --git a/src/engine/external/libwebsockets/output.c b/src/engine/external/libwebsockets/output.c new file mode 100644 index 00000000..b914f281 --- /dev/null +++ b/src/engine/external/libwebsockets/output.c @@ -0,0 +1,606 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +static int +libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi) +{ + int n; + + /* fetch the per-frame nonce */ + + n = libwebsockets_get_random(wsi->protocol->owning_server, + wsi->u.ws.frame_masking_nonce_04, 4); + if (n != 4) { + lwsl_parser("Unable to read from random device %s %d\n", + SYSTEM_RANDOM_FILEPATH, n); + return 1; + } + + /* start masking from first byte of masking key buffer */ + wsi->u.ws.frame_mask_index = 0; + + return 0; +} + +#ifdef _DEBUG + +LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len) +{ + int n; + int m; + int start; + unsigned char *buf = (unsigned char *)vbuf; + char line[80]; + char *p; + + lwsl_parser("\n"); + + for (n = 0; n < len;) { + start = n; + p = line; + + p += sprintf(p, "%04X: ", start); + + for (m = 0; m < 16 && n < len; m++) + p += sprintf(p, "%02X ", buf[n++]); + while (m++ < 16) + p += sprintf(p, " "); + + p += sprintf(p, " "); + + for (m = 0; m < 16 && (start + m) < len; m++) { + if (buf[start + m] >= ' ' && buf[start + m] < 127) + *p++ = buf[start + m]; + else + *p++ = '.'; + } + while (m++ < 16) + *p++ = ' '; + + *p++ = '\n'; + *p = '\0'; + lwsl_debug("%s", line); + } + lwsl_debug("\n"); +} + +#endif + +/* + * notice this returns number of bytes consumed, or -1 + */ + +int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len) +{ + struct libwebsocket_context *context = wsi->protocol->owning_server; + int n; + size_t real_len = len; + int m; + + if (!len) + return 0; + /* just ignore sends after we cleared the truncation buffer */ + if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE && + !wsi->truncated_send_len) + return len; + + if (wsi->truncated_send_len && (buf < wsi->truncated_send_malloc || + buf > (wsi->truncated_send_malloc + + wsi->truncated_send_len + + wsi->truncated_send_offset))) { + lwsl_err("****** %x Sending new, pending truncated ...\n", wsi); + assert(0); + } + + m = lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, &buf, len); + if (m < 0) + return -1; + if (m) /* handled */ { + n = m; + goto handle_truncated_send; + } + if (wsi->sock < 0) + lwsl_warn("** error invalid sock but expected to send\n"); + + /* + * nope, send it on the socket directly + */ + lws_latency_pre(context, wsi); + n = lws_ssl_capable_write(wsi, buf, len); + lws_latency(context, wsi, "send lws_issue_raw", n, n == len); + + switch (n) { + case LWS_SSL_CAPABLE_ERROR: + /* we're going to close, let close know sends aren't possible */ + wsi->socket_is_permanently_unusable = 1; + return -1; + case LWS_SSL_CAPABLE_MORE_SERVICE: + /* nothing got sent, not fatal, retry the whole thing later */ + n = 0; + break; + } + +handle_truncated_send: + /* + * we were already handling a truncated send? + */ + if (wsi->truncated_send_len) { + lwsl_info("***** %x partial send moved on by %d (vs %d)\n", + wsi, n, real_len); + wsi->truncated_send_offset += n; + wsi->truncated_send_len -= n; + + if (!wsi->truncated_send_len) { + lwsl_info("***** %x partial send completed\n", wsi); + /* done with it, but don't free it */ + n = real_len; + if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) { + lwsl_info("***** %x signalling to close now\n", wsi); + return -1; /* retry closing now */ + } + } + /* always callback on writeable */ + libwebsocket_callback_on_writable( + wsi->protocol->owning_server, wsi); + + return n; + } + + if (n == real_len) + /* what we just sent went out cleanly */ + return n; + + if (n && wsi->u.ws.clean_buffer) + /* + * This buffer unaffected by extension rewriting. + * It means the user code is expected to deal with + * partial sends. (lws knows the header was already + * sent, so on next send will just resume sending + * payload) + */ + return n; + + /* + * Newly truncated send. Buffer the remainder (it will get + * first priority next time the socket is writable) + */ + lwsl_info("***** %x new partial sent %d from %d total\n", + wsi, n, real_len); + + /* + * - if we still have a suitable malloc lying around, use it + * - or, if too small, reallocate it + * - or, if no buffer, create it + */ + if (!wsi->truncated_send_malloc || + real_len - n > wsi->truncated_send_allocation) { + lws_free(wsi->truncated_send_malloc); + + wsi->truncated_send_allocation = real_len - n; + wsi->truncated_send_malloc = lws_malloc(real_len - n); + if (!wsi->truncated_send_malloc) { + lwsl_err("truncated send: unable to malloc %d\n", + real_len - n); + return -1; + } + } + wsi->truncated_send_offset = 0; + wsi->truncated_send_len = real_len - n; + memcpy(wsi->truncated_send_malloc, buf + n, real_len - n); + + /* since something buffered, force it to get another chance to send */ + libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi); + + return real_len; +} + +/** + * 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. + * + * 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. + * + * Return may be -1 for a fatal error needing connection close, or a + * positive number reflecting the amount of bytes actually sent. This + * can be less than the requested number of bytes due to OS memory + * pressure at any given time. + */ + +LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, + size_t len, enum libwebsocket_write_protocol protocol) +{ + int n; + int pre = 0; + int post = 0; + int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT; + unsigned char *dropmask = NULL; + unsigned char is_masked_bit = 0; + size_t orig_len = len; + struct lws_tokens eff_buf; + + if (len == 0 && protocol != LWS_WRITE_CLOSE && + protocol != LWS_WRITE_PING && protocol != LWS_WRITE_PONG) { + lwsl_warn("zero length libwebsocket_write attempt\n"); + return 0; + } + + if (protocol == LWS_WRITE_HTTP || + protocol == LWS_WRITE_HTTP_FINAL || + protocol == LWS_WRITE_HTTP_HEADERS) + goto send_raw; + + /* websocket protocol, either binary or text */ + + if (wsi->state != WSI_STATE_ESTABLISHED) + return -1; + + /* if we are continuing a frame that already had its header done */ + + if (wsi->u.ws.inside_frame) + goto do_more_inside_frame; + + wsi->u.ws.clean_buffer = 1; + + /* + * give a chance to the extensions to modify payload + * pre-TX mangling is not allowed to truncate + */ + eff_buf.token = (char *)buf; + eff_buf.token_len = len; + + switch (protocol) { + case LWS_WRITE_PING: + case LWS_WRITE_PONG: + case LWS_WRITE_CLOSE: + break; + default: + if (lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_PAYLOAD_TX, &eff_buf, 0) < 0) + return -1; + } + + /* + * an extension did something we need to keep... for example, if + * compression extension, it has already updated its state according + * to this being issued + */ + if ((char *)buf != eff_buf.token) + /* + * extension recreated it: + * need to buffer this if not all sent + */ + wsi->u.ws.clean_buffer = 0; + + buf = (unsigned char *)eff_buf.token; + len = eff_buf.token_len; + + switch (wsi->ietf_spec_revision) { + case 13: + + if (masked7) { + pre += 4; + dropmask = &buf[0 - pre]; + is_masked_bit = 0x80; + } + + switch (protocol & 0xf) { + case LWS_WRITE_TEXT: + n = LWS_WS_OPCODE_07__TEXT_FRAME; + break; + case LWS_WRITE_BINARY: + n = LWS_WS_OPCODE_07__BINARY_FRAME; + break; + case LWS_WRITE_CONTINUATION: + n = LWS_WS_OPCODE_07__CONTINUATION; + break; + + case LWS_WRITE_CLOSE: + n = LWS_WS_OPCODE_07__CLOSE; + + /* + * 06+ has a 2-byte status code in network order + * we can do this because we demand post-buf + */ + + if (wsi->u.ws.close_reason) { + /* reason codes count as data bytes */ + buf -= 2; + buf[0] = wsi->u.ws.close_reason >> 8; + buf[1] = wsi->u.ws.close_reason; + len += 2; + } + break; + case LWS_WRITE_PING: + n = LWS_WS_OPCODE_07__PING; + break; + case LWS_WRITE_PONG: + n = LWS_WS_OPCODE_07__PONG; + break; + default: + lwsl_warn("lws_write: unknown write opc / protocol\n"); + return -1; + } + + if (!(protocol & LWS_WRITE_NO_FIN)) + n |= 1 << 7; + + if (len < 126) { + pre += 2; + buf[-pre] = n; + buf[-pre + 1] = len | is_masked_bit; + } else { + if (len < 65536) { + pre += 4; + buf[-pre] = n; + buf[-pre + 1] = 126 | is_masked_bit; + buf[-pre + 2] = len >> 8; + buf[-pre + 3] = len; + } else { + pre += 10; + buf[-pre] = n; + buf[-pre + 1] = 127 | is_masked_bit; +#if defined __LP64__ + buf[-pre + 2] = (len >> 56) & 0x7f; + buf[-pre + 3] = len >> 48; + buf[-pre + 4] = len >> 40; + buf[-pre + 5] = len >> 32; +#else + buf[-pre + 2] = 0; + buf[-pre + 3] = 0; + buf[-pre + 4] = 0; + buf[-pre + 5] = 0; +#endif + buf[-pre + 6] = len >> 24; + buf[-pre + 7] = len >> 16; + buf[-pre + 8] = len >> 8; + buf[-pre + 9] = len; + } + } + break; + } + +do_more_inside_frame: + + /* + * Deal with masking if we are in client -> server direction and + * the protocol demands it + */ + + if (wsi->mode == LWS_CONNMODE_WS_CLIENT) { + + if (!wsi->u.ws.inside_frame) + if (libwebsocket_0405_frame_mask_generate(wsi)) { + lwsl_err("frame mask generation failed\n"); + return -1; + } + + /* + * in v7, just mask the payload + */ + if (dropmask) { /* never set if already inside frame */ + for (n = 4; n < (int)len + 4; n++) + dropmask[n] = dropmask[n] ^ + wsi->u.ws.frame_masking_nonce_04[ + (wsi->u.ws.frame_mask_index++) & 3]; + + /* copy the frame nonce into place */ + memcpy(dropmask, wsi->u.ws.frame_masking_nonce_04, 4); + } + } + +send_raw: + switch (protocol) { + case LWS_WRITE_CLOSE: +/* lwsl_hexdump(&buf[-pre], len + post); */ + case LWS_WRITE_HTTP: + case LWS_WRITE_HTTP_FINAL: + case LWS_WRITE_HTTP_HEADERS: + case LWS_WRITE_PONG: + case LWS_WRITE_PING: +#ifdef LWS_USE_HTTP2 + if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) { + unsigned char flags = 0; + + n = LWS_HTTP2_FRAME_TYPE_DATA; + if (protocol == LWS_WRITE_HTTP_HEADERS) { + n = LWS_HTTP2_FRAME_TYPE_HEADERS; + flags = LWS_HTTP2_FLAG_END_HEADERS; + if (wsi->u.http2.send_END_STREAM) + flags |= LWS_HTTP2_FLAG_END_STREAM; + } + + if ((protocol == LWS_WRITE_HTTP || protocol == LWS_WRITE_HTTP_FINAL) && wsi->u.http.content_length) { + wsi->u.http.content_remain -= len; + lwsl_info("%s: content_remain = %lu\n", __func__, wsi->u.http.content_remain); + if (!wsi->u.http.content_remain) { + lwsl_info("%s: selecting final write mode\n", __func__); + protocol = LWS_WRITE_HTTP_FINAL; + } + } + + if (protocol == LWS_WRITE_HTTP_FINAL && wsi->u.http2.END_STREAM) { + lwsl_info("%s: setting END_STREAM\n", __func__); + flags |= LWS_HTTP2_FLAG_END_STREAM; + } + + return lws_http2_frame_write(wsi, n, flags, wsi->u.http2.my_stream_id, len, buf); + } +#endif + return lws_issue_raw(wsi, (unsigned char *)buf - pre, + len + pre + post); + default: + break; + } + + wsi->u.ws.inside_frame = 1; + + /* + * give any active extensions a chance to munge the buffer + * before send. We pass in a pointer to an lws_tokens struct + * prepared with the default buffer and content length that's in + * there. Rather than rewrite the default buffer, extensions + * that expect to grow the buffer can adapt .token to + * point to their own per-connection buffer in the extension + * user allocation. By default with no extensions or no + * extension callback handling, just the normal input buffer is + * used then so it is efficient. + * + * callback returns 1 in case it wants to spill more buffers + * + * This takes care of holding the buffer if send is incomplete, ie, + * if wsi->u.ws.clean_buffer is 0 (meaning an extension meddled with + * the buffer). If wsi->u.ws.clean_buffer is 1, it will instead + * return to the user code how much OF THE USER BUFFER was consumed. + */ + + n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post); + if (n <= 0) + return n; + + if (n == len + pre + post) { + /* everything in the buffer was handled (or rebuffered...) */ + wsi->u.ws.inside_frame = 0; + return orig_len; + } + + /* + * it is how many bytes of user buffer got sent... may be < orig_len + * in which case callback when writable has already been arranged + * and user code can call libwebsocket_write() again with the rest + * later. + */ + + return n - (pre + post); +} + +LWS_VISIBLE int libwebsockets_serve_http_file_fragment( + struct libwebsocket_context *context, struct libwebsocket *wsi) +{ + int n; + int m; + + while (!lws_send_pipe_choked(wsi)) { + + if (wsi->truncated_send_len) { + if (lws_issue_raw(wsi, wsi->truncated_send_malloc + + wsi->truncated_send_offset, + wsi->truncated_send_len) < 0) { + lwsl_info("closing from libwebsockets_serve_http_file_fragment\n"); + return -1; + } + continue; + } + + if (wsi->u.http.filepos == wsi->u.http.filelen) + goto all_sent; + + compatible_file_read(n, wsi->u.http.fd, context->service_buffer, + sizeof(context->service_buffer)); + if (n < 0) + return -1; /* caller will close */ + if (n) { + wsi->u.http.filepos += n; + m = libwebsocket_write(wsi, context->service_buffer, n, + wsi->u.http.filepos == wsi->u.http.filelen ? LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP); + if (m < 0) + return -1; + + if (m != n) + /* adjust for what was not sent */ + if (compatible_file_seek_cur(wsi->u.http.fd, m - n) < 0) + return -1; + } +all_sent: + if (!wsi->truncated_send_len && + wsi->u.http.filepos == wsi->u.http.filelen) { + wsi->state = WSI_STATE_HTTP; + + if (wsi->protocol->callback) + /* ignore callback returned value */ + user_callback_handle_rxflow( + wsi->protocol->callback, context, wsi, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + wsi->user_space, NULL, 0); + return 1; /* >0 indicates completed */ + } + } + + lwsl_info("choked before able to send whole file (post)\n"); + libwebsocket_callback_on_writable(context, wsi); + + return 0; /* indicates further processing must be done */ +} + +LWS_VISIBLE int +lws_ssl_capable_read_no_ssl(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char *buf, int len) +{ + int n; + + n = recv(wsi->sock, buf, len, 0); + if (n >= 0) + return n; + + lwsl_warn("error on reading from skt\n"); + return LWS_SSL_CAPABLE_ERROR; +} + +LWS_VISIBLE int +lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len) +{ + int n; + + n = send(wsi->sock, buf, len, 0); + if (n >= 0) + return n; + + if (LWS_ERRNO == LWS_EAGAIN || + LWS_ERRNO == LWS_EWOULDBLOCK || + LWS_ERRNO == LWS_EINTR) { + if (LWS_ERRNO == LWS_EWOULDBLOCK) + lws_set_blocking_send(wsi); + + return LWS_SSL_CAPABLE_MORE_SERVICE; + } + lwsl_debug("ERROR writing len %d to skt %d\n", len, n); + return LWS_SSL_CAPABLE_ERROR; +} diff --git a/src/engine/external/libwebsockets/parsers.c b/src/engine/external/libwebsockets/parsers.c new file mode 100644 index 00000000..2b4a900b --- /dev/null +++ b/src/engine/external/libwebsockets/parsers.c @@ -0,0 +1,1015 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +unsigned char lextable[] = { + #include "lextable.h" +}; + +#define FAIL_CHAR 0x08 + +int lextable_decode(int pos, char c) +{ + + c = tolower(c); + + while (1) { + if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */ + if ((lextable[pos] & 0x7f) != c) + return -1; + /* fall thru */ + pos++; + if (lextable[pos] == FAIL_CHAR) + return -1; + return pos; + } + + if (lextable[pos] == FAIL_CHAR) + return -1; + + /* b7 = 0, end or 3-byte */ + if (lextable[pos] < FAIL_CHAR) /* terminal marker */ + return pos; + + if (lextable[pos] == c) /* goto */ + return pos + (lextable[pos + 1]) + + (lextable[pos + 2] << 8); + /* fall thru goto */ + pos += 3; + /* continue */ + } +} + +int lws_allocate_header_table(struct libwebsocket *wsi) +{ + /* Be sure to free any existing header data to avoid mem leak: */ + lws_free_header_table(wsi); + wsi->u.hdr.ah = lws_malloc(sizeof(*wsi->u.hdr.ah)); + if (wsi->u.hdr.ah == NULL) { + lwsl_err("Out of memory\n"); + return -1; + } + memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index)); + wsi->u.hdr.ah->next_frag_index = 0; + wsi->u.hdr.ah->pos = 0; + + return 0; +} + +int lws_free_header_table(struct libwebsocket *wsi) +{ + lws_free2(wsi->u.hdr.ah); + wsi->u.hdr.ah = NULL; + return 0; +}; + +LWS_VISIBLE int lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h) +{ + int n; + int len = 0; + + n = wsi->u.hdr.ah->frag_index[h]; + if (!n) + return 0; + do { + len += wsi->u.hdr.ah->frags[n].len; + n = wsi->u.hdr.ah->frags[n].next_frag_index; + } while (n); + + return len; +} + +LWS_VISIBLE int lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h) +{ + int toklen = lws_hdr_total_length(wsi, h); + int n; + + if (toklen >= len) + return -1; + + n = wsi->u.hdr.ah->frag_index[h]; + if (!n) + return 0; + + do { + strcpy(dest, + &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]); + dest += wsi->u.hdr.ah->frags[n].len; + n = wsi->u.hdr.ah->frags[n].next_frag_index; + } while (n); + + return toklen; +} + +char *lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h) +{ + int n; + + n = wsi->u.hdr.ah->frag_index[h]; + if (!n) + return NULL; + + return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]; +} + +int lws_hdr_simple_create(struct libwebsocket *wsi, + enum lws_token_indexes h, const char *s) +{ + wsi->u.hdr.ah->next_frag_index++; + if (wsi->u.hdr.ah->next_frag_index == + sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) { + lwsl_warn("More hdr frags than we can deal with, dropping\n"); + return -1; + } + + wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index; + + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset = + wsi->u.hdr.ah->pos; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index = + 0; + + do { + if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) { + lwsl_err("Ran out of header data space\n"); + return -1; + } + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s; + if (*s) + wsi->u.hdr.ah->frags[ + wsi->u.hdr.ah->next_frag_index].len++; + } while (*s++); + + return 0; +} + +static char char_to_hex(const char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; +} + +static int issue_char(struct libwebsocket *wsi, unsigned char c) +{ + if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) { + lwsl_warn("excessive header content\n"); + return -1; + } + + if( wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len >= + wsi->u.hdr.current_token_limit) { + lwsl_warn("header %i exceeds limit\n", wsi->u.hdr.parser_state); + return 1; + }; + + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c; + if (c) + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++; + + return 0; +} + +int libwebsocket_parse( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char c) +{ + int n; + + switch (wsi->u.hdr.parser_state) { + default: + + lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c); + + /* collect into malloc'd buffers */ + /* optional initial space swallow */ + if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[ + wsi->u.hdr.parser_state]].len && c == ' ') + break; + + if ((wsi->u.hdr.parser_state != WSI_TOKEN_GET_URI) && + (wsi->u.hdr.parser_state != WSI_TOKEN_POST_URI) && + (wsi->u.hdr.parser_state != WSI_TOKEN_OPTIONS_URI)) + goto check_eol; + + /* special URI processing... end at space */ + + if (c == ' ') { + /* enforce starting with / */ + if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len) + if (issue_char(wsi, '/') < 0) + return -1; + + /* begin parsing HTTP version: */ + if (issue_char(wsi, '\0') < 0) + return -1; + wsi->u.hdr.parser_state = WSI_TOKEN_HTTP; + goto start_fragment; + } + + /* special URI processing... convert %xx */ + + switch (wsi->u.hdr.ues) { + case URIES_IDLE: + if (c == '%') { + wsi->u.hdr.ues = URIES_SEEN_PERCENT; + goto swallow; + } + break; + case URIES_SEEN_PERCENT: + if (char_to_hex(c) < 0) { + /* regurgitate */ + if (issue_char(wsi, '%') < 0) + return -1; + wsi->u.hdr.ues = URIES_IDLE; + /* continue on to assess c */ + break; + } + wsi->u.hdr.esc_stash = c; + wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1; + goto swallow; + + case URIES_SEEN_PERCENT_H1: + if (char_to_hex(c) < 0) { + /* regurgitate */ + issue_char(wsi, '%'); + wsi->u.hdr.ues = URIES_IDLE; + /* regurgitate + assess */ + if (libwebsocket_parse(context, wsi, wsi->u.hdr.esc_stash) < 0) + return -1; + /* continue on to assess c */ + break; + } + c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) | + char_to_hex(c); + wsi->u.hdr.ues = URIES_IDLE; + break; + } + + /* + * special URI processing... + * convert /.. or /... or /../ etc to / + * convert /./ to / + * convert // or /// etc to / + * leave /.dir or whatever alone + */ + + switch (wsi->u.hdr.ups) { + case URIPS_IDLE: + /* issue the first / always */ + if (c == '/') + wsi->u.hdr.ups = URIPS_SEEN_SLASH; + break; + case URIPS_SEEN_SLASH: + /* swallow subsequent slashes */ + if (c == '/') + goto swallow; + /* track and swallow the first . after / */ + if (c == '.') { + wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT; + goto swallow; + } + wsi->u.hdr.ups = URIPS_IDLE; + break; + case URIPS_SEEN_SLASH_DOT: + /* swallow second . */ + if (c == '.') { + /* + * back up one dir level if possible + * safe against header fragmentation because + * the method URI can only be in 1 fragment + */ + if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) { + wsi->u.hdr.ah->pos--; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--; + do { + wsi->u.hdr.ah->pos--; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--; + } while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 && + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/'); + } + wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT; + goto swallow; + } + /* change /./ to / */ + if (c == '/') { + wsi->u.hdr.ups = URIPS_SEEN_SLASH; + goto swallow; + } + /* it was like /.dir ... regurgitate the . */ + wsi->u.hdr.ups = URIPS_IDLE; + issue_char(wsi, '.'); + break; + + case URIPS_SEEN_SLASH_DOT_DOT: + /* swallow prior .. chars and any subsequent . */ + if (c == '.') + goto swallow; + /* last issued was /, so another / == // */ + if (c == '/') + goto swallow; + /* last we issued was / so SEEN_SLASH */ + wsi->u.hdr.ups = URIPS_SEEN_SLASH; + break; + case URIPS_ARGUMENTS: + /* leave them alone */ + break; + } + + if (c == '?') { /* start of URI arguments */ + /* seal off uri header */ + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0'; + + /* move to using WSI_TOKEN_HTTP_URI_ARGS */ + wsi->u.hdr.ah->next_frag_index++; + wsi->u.hdr.ah->frags[ + wsi->u.hdr.ah->next_frag_index].offset = + wsi->u.hdr.ah->pos; + wsi->u.hdr.ah->frags[ + wsi->u.hdr.ah->next_frag_index].len = 0; + wsi->u.hdr.ah->frags[ + wsi->u.hdr.ah->next_frag_index].next_frag_index = 0; + + wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = + wsi->u.hdr.ah->next_frag_index; + + /* defeat normal uri path processing */ + wsi->u.hdr.ups = URIPS_ARGUMENTS; + goto swallow; + } + +check_eol: + + /* bail at EOL */ + if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE && + c == '\x0d') { + c = '\0'; + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR; + lwsl_parser("*\n"); + } + + n = issue_char(wsi, c); + if (n < 0) + return -1; + if (n > 0) + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + +swallow: + /* per-protocol end of headers management */ + + if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE) + goto set_parsing_complete; + break; + + /* collecting and checking a name part */ + case WSI_TOKEN_NAME_PART: + lwsl_parser("WSI_TOKEN_NAME_PART '%c'\n", c); + + wsi->u.hdr.lextable_pos = + lextable_decode(wsi->u.hdr.lextable_pos, c); + + if (wsi->u.hdr.lextable_pos < 0) { + /* this is not a header we know about */ + if (wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI] || + wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI] || + wsi->u.hdr.ah->frag_index[WSI_TOKEN_OPTIONS_URI] || + wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP]) { + /* + * already had the method, no idea what + * this crap is, ignore + */ + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + break; + } + /* + * hm it's an unknown http method in fact, + * treat as dangerous + */ + + lwsl_info("Unknown method - dropping\n"); + return -1; + } + if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) { + + /* terminal state */ + + n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) | + lextable[wsi->u.hdr.lextable_pos + 1]; + + lwsl_parser("known hdr %d\n", n); + if (n == WSI_TOKEN_GET_URI && + wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI]) { + lwsl_warn("Duplicated GET\n"); + return -1; + } + if (n == WSI_TOKEN_POST_URI && + wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI]) { + lwsl_warn("Duplicated POST\n"); + return -1; + } + if (n == WSI_TOKEN_OPTIONS_URI && + wsi->u.hdr.ah->frag_index[WSI_TOKEN_OPTIONS_URI]) { + lwsl_warn("Duplicated OPTIONS\n"); + return -1; + } + + /* + * WSORIGIN is protocol equiv to ORIGIN, + * JWebSocket likes to send it, map to ORIGIN + */ + if (n == WSI_TOKEN_SWORIGIN) + n = WSI_TOKEN_ORIGIN; + + wsi->u.hdr.parser_state = (enum lws_token_indexes) + (WSI_TOKEN_GET_URI + n); + + if (context->token_limits) + wsi->u.hdr.current_token_limit = + context->token_limits->token_limit[wsi->u.hdr.parser_state]; + else + wsi->u.hdr.current_token_limit = sizeof(wsi->u.hdr.ah->data); + + if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE) + goto set_parsing_complete; + + goto start_fragment; + } + break; + +start_fragment: + wsi->u.hdr.ah->next_frag_index++; + if (wsi->u.hdr.ah->next_frag_index == + sizeof(wsi->u.hdr.ah->frags) / + sizeof(wsi->u.hdr.ah->frags[0])) { + lwsl_warn("More hdr frags than we can deal with\n"); + return -1; + } + + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset = + wsi->u.hdr.ah->pos; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0; + wsi->u.hdr.ah->frags[ + wsi->u.hdr.ah->next_frag_index].next_frag_index = 0; + + n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state]; + if (!n) { /* first fragment */ + wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] = + wsi->u.hdr.ah->next_frag_index; + break; + } + /* continuation */ + while (wsi->u.hdr.ah->frags[n].next_frag_index) + n = wsi->u.hdr.ah->frags[n].next_frag_index; + wsi->u.hdr.ah->frags[n].next_frag_index = + wsi->u.hdr.ah->next_frag_index; + + if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) { + lwsl_warn("excessive header content\n"); + return -1; + } + + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' '; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++; + break; + + /* skipping arg part of a name we didn't recognize */ + case WSI_TOKEN_SKIPPING: + lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c); + + if (c == '\x0d') + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR; + break; + + case WSI_TOKEN_SKIPPING_SAW_CR: + lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c); + if (c == '\x0a') { + wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; + wsi->u.hdr.lextable_pos = 0; + } else + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + break; + /* we're done, ignore anything else */ + + case WSI_PARSING_COMPLETE: + lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c); + break; + } + + return 0; + +set_parsing_complete: + + if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) { + if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION)) + wsi->ietf_spec_revision = + atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION)); + + lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision); + } + wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE; + wsi->hdr_parsing_completed = 1; + + return 0; +} + + +/** + * lws_frame_is_binary: true if the current frame was sent in binary mode + * + * @wsi: the connection we are inquiring about + * + * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if + * it's interested to see if the frame it's dealing with was sent in binary + * mode. + */ + +LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi) +{ + return wsi->u.ws.frame_is_binary; +} + +int +libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) +{ + int n; + struct lws_tokens eff_buf; + int ret = 0; + + switch (wsi->lws_rx_parse_state) { + case LWS_RXPS_NEW: + + switch (wsi->ietf_spec_revision) { + case 13: + /* + * no prepended frame key any more + */ + wsi->u.ws.all_zero_nonce = 1; + goto handle_first; + + default: + lwsl_warn("lws_rx_sm: unknown spec version %d\n", + wsi->ietf_spec_revision); + break; + } + break; + case LWS_RXPS_04_MASK_NONCE_1: + wsi->u.ws.frame_masking_nonce_04[1] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2; + break; + case LWS_RXPS_04_MASK_NONCE_2: + wsi->u.ws.frame_masking_nonce_04[2] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3; + break; + case LWS_RXPS_04_MASK_NONCE_3: + wsi->u.ws.frame_masking_nonce_04[3] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + + /* + * start from the zero'th byte in the XOR key buffer since + * this is the start of a frame with a new key + */ + + wsi->u.ws.frame_mask_index = 0; + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1; + break; + + /* + * 04 logical framing from the spec (all this is masked when incoming + * and has to be unmasked) + * + * We ignore the possibility of extension data because we don't + * negotiate any extensions at the moment. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|R| Payload len | Extended payload length | + * |I|S|S|S| (4) |S| (7) | (16/63) | + * |N|V|V|V| |V| | (if payload len==126/127) | + * | |1|2|3| |4| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | | Extension data | + * +-------------------------------+ - - - - - - - - - - - - - - - + + * : : + * +---------------------------------------------------------------+ + * : Application data : + * +---------------------------------------------------------------+ + * + * We pass payload through to userland as soon as we get it, ignoring + * FIN. It's up to userland to buffer it up if it wants to see a + * whole unfragmented block of the original size (which may be up to + * 2^63 long!) + */ + + case LWS_RXPS_04_FRAME_HDR_1: +handle_first: + + wsi->u.ws.opcode = c & 0xf; + wsi->u.ws.rsv = c & 0x70; + wsi->u.ws.final = !!((c >> 7) & 1); + + switch (wsi->u.ws.opcode) { + case LWS_WS_OPCODE_07__TEXT_FRAME: + case LWS_WS_OPCODE_07__BINARY_FRAME: + wsi->u.ws.frame_is_binary = + wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME; + break; + } + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN: + + wsi->u.ws.this_frame_masked = !!(c & 0x80); + + switch (c & 0x7f) { + case 126: + /* control frames are not allowed to have big lengths */ + if (wsi->u.ws.opcode & 8) + goto illegal_ctl_length; + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2; + break; + case 127: + /* control frames are not allowed to have big lengths */ + if (wsi->u.ws.opcode & 8) + goto illegal_ctl_length; + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8; + break; + default: + wsi->u.ws.rx_packet_length = c & 0x7f; + if (wsi->u.ws.this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + if (wsi->u.ws.rx_packet_length) + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + else { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + break; + } + break; + + case LWS_RXPS_04_FRAME_HDR_LEN16_2: + wsi->u.ws.rx_packet_length = c << 8; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN16_1: + wsi->u.ws.rx_packet_length |= c; + if (wsi->u.ws.this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_8: + if (c & 0x80) { + lwsl_warn("b63 of length must be zero\n"); + /* kill the connection */ + return -1; + } +#if defined __LP64__ + wsi->u.ws.rx_packet_length = ((size_t)c) << 56; +#else + wsi->u.ws.rx_packet_length = 0; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_7: +#if defined __LP64__ + wsi->u.ws.rx_packet_length |= ((size_t)c) << 48; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_6: +#if defined __LP64__ + wsi->u.ws.rx_packet_length |= ((size_t)c) << 40; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_5: +#if defined __LP64__ + wsi->u.ws.rx_packet_length |= ((size_t)c) << 32; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_4: + wsi->u.ws.rx_packet_length |= ((size_t)c) << 24; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_3: + wsi->u.ws.rx_packet_length |= ((size_t)c) << 16; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_2: + wsi->u.ws.rx_packet_length |= ((size_t)c) << 8; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_1: + wsi->u.ws.rx_packet_length |= ((size_t)c); + if (wsi->u.ws.this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_1: + wsi->u.ws.frame_masking_nonce_04[0] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_2: + wsi->u.ws.frame_masking_nonce_04[1] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_3: + wsi->u.ws.frame_masking_nonce_04[2] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_4: + wsi->u.ws.frame_masking_nonce_04[3] = c; + if (c) + wsi->u.ws.all_zero_nonce = 0; + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + wsi->u.ws.frame_mask_index = 0; + if (wsi->u.ws.rx_packet_length == 0) { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + break; + + + case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: + + if (!wsi->u.ws.rx_user_buffer) { + lwsl_err("NULL user buffer...\n"); + return 1; + } + + if (wsi->u.ws.all_zero_nonce) + wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->u.ws.rx_user_buffer_head++)] = c; + else + wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->u.ws.rx_user_buffer_head++)] = + c ^ wsi->u.ws.frame_masking_nonce_04[ + (wsi->u.ws.frame_mask_index++) & 3]; + + if (--wsi->u.ws.rx_packet_length == 0) { + /* spill because we have the whole frame */ + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + + /* + * if there's no protocol max frame size given, we are + * supposed to default to LWS_MAX_SOCKET_IO_BUF + */ + + if (!wsi->protocol->rx_buffer_size && + wsi->u.ws.rx_user_buffer_head != + LWS_MAX_SOCKET_IO_BUF) + break; + else + if (wsi->protocol->rx_buffer_size && + wsi->u.ws.rx_user_buffer_head != + wsi->protocol->rx_buffer_size) + break; + + /* spill because we filled our rx buffer */ +spill: + /* + * is this frame a control packet we should take care of at this + * layer? If so service it and hide it from the user callback + */ + + lwsl_parser("spill on %s\n", wsi->protocol->name); + + switch (wsi->u.ws.opcode) { + case LWS_WS_OPCODE_07__CLOSE: + /* is this an acknowledgement of our close? */ + if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) { + /* + * fine he has told us he is closing too, let's + * finish our close + */ + lwsl_parser("seen client close ack\n"); + return -1; + } + lwsl_parser("server sees client close packet\n"); + /* parrot the close packet payload back */ + n = libwebsocket_write(wsi, (unsigned char *) + &wsi->u.ws.rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING], + wsi->u.ws.rx_user_buffer_head, + LWS_WRITE_CLOSE); + if (n < 0) + lwsl_info("write of close ack failed %d\n", n); + wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY; + /* close the connection */ + return -1; + + case LWS_WS_OPCODE_07__PING: + lwsl_info("received %d byte ping, sending pong\n", + wsi->u.ws.rx_user_buffer_head); + + if (wsi->u.ws.ping_payload_len) { + /* + * there is already a pending ping payload + * we should just log and drop + */ + lwsl_parser("DROP PING since one pending\n"); + goto ping_drop; + } + + /* control packets can only be < 128 bytes long */ + if (wsi->u.ws.ping_payload_len > 128 - 4) { + lwsl_parser("DROP PING payload too large\n"); + goto ping_drop; + } + + /* if existing buffer is too small, drop it */ + if (wsi->u.ws.ping_payload_buf && + wsi->u.ws.ping_payload_alloc < wsi->u.ws.rx_user_buffer_head) { + lws_free2(wsi->u.ws.ping_payload_buf); + } + + /* if no buffer, allocate it */ + if (!wsi->u.ws.ping_payload_buf) { + wsi->u.ws.ping_payload_buf = lws_malloc(wsi->u.ws.rx_user_buffer_head + + LWS_SEND_BUFFER_PRE_PADDING); + wsi->u.ws.ping_payload_alloc = wsi->u.ws.rx_user_buffer_head; + } + + /* stash the pong payload */ + memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING, + &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->u.ws.rx_user_buffer_head); + + wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head; + + /* get it sent as soon as possible */ + libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi); +ping_drop: + wsi->u.ws.rx_user_buffer_head = 0; + return 0; + + case LWS_WS_OPCODE_07__PONG: + /* ... then just drop it */ + wsi->u.ws.rx_user_buffer_head = 0; + return 0; + + case LWS_WS_OPCODE_07__TEXT_FRAME: + case LWS_WS_OPCODE_07__BINARY_FRAME: + case LWS_WS_OPCODE_07__CONTINUATION: + break; + + default: + lwsl_parser("passing opc %x up to exts\n", + wsi->u.ws.opcode); + /* + * It's something special we can't understand here. + * Pass the payload up to the extension's parsing + * state machine. + */ + + eff_buf.token = &wsi->u.ws.rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING]; + eff_buf.token_len = wsi->u.ws.rx_user_buffer_head; + + if (lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + &eff_buf, 0) <= 0) /* not handle or fail */ + lwsl_ext("ext opc opcode 0x%x unknown\n", + wsi->u.ws.opcode); + + wsi->u.ws.rx_user_buffer_head = 0; + return 0; + } + + /* + * No it's real payload, pass it up to the user callback. + * It's nicely buffered with the pre-padding taken care of + * so it can be sent straight out again using libwebsocket_write + */ + + eff_buf.token = &wsi->u.ws.rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING]; + eff_buf.token_len = wsi->u.ws.rx_user_buffer_head; + + if (lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_PAYLOAD_RX, &eff_buf, 0) < 0) + return -1; + + if (eff_buf.token_len > 0) { + eff_buf.token[eff_buf.token_len] = '\0'; + + if (wsi->protocol->callback) + ret = user_callback_handle_rxflow( + wsi->protocol->callback, + wsi->protocol->owning_server, + wsi, LWS_CALLBACK_RECEIVE, + wsi->user_space, + eff_buf.token, + eff_buf.token_len); + else + lwsl_err("No callback on payload spill!\n"); + } + + wsi->u.ws.rx_user_buffer_head = 0; + break; + } + + return ret; + +illegal_ctl_length: + + lwsl_warn("Control frame with xtended length is illegal\n"); + /* kill the connection */ + return -1; +} + + +/** + * libwebsockets_remaining_packet_payload() - Bytes to come before "overall" + * rx packet is complete + * @wsi: Websocket instance (available from user callback) + * + * This function is intended to be called from the callback if the + * user code is interested in "complete packets" from the client. + * libwebsockets just passes through payload as it comes and issues a buffer + * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE + * callback handler can use this API to find out if the buffer it has just + * been given is the last piece of a "complete packet" from the client -- + * when that is the case libwebsockets_remaining_packet_payload() will return + * 0. + * + * Many protocols won't care becuse their packets are always small. + */ + +LWS_VISIBLE size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi) +{ + return wsi->u.ws.rx_packet_length; +} diff --git a/src/engine/external/libwebsockets/pollfd.c b/src/engine/external/libwebsockets/pollfd.c new file mode 100644 index 00000000..b09127e0 --- /dev/null +++ b/src/engine/external/libwebsockets/pollfd.c @@ -0,0 +1,293 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +int +insert_wsi_socket_into_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + struct libwebsocket_pollargs pa = { wsi->sock, LWS_POLLIN, 0 }; + + if (context->fds_count >= context->max_fds) { + lwsl_err("Too many fds (%d)\n", context->max_fds); + return 1; + } + + if (wsi->sock >= context->max_fds) { + lwsl_err("Socket fd %d is too high (%d)\n", + wsi->sock, context->max_fds); + return 1; + } + + assert(wsi); + assert(wsi->sock >= 0); + + lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n", + wsi, wsi->sock, context->fds_count); + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_LOCK_POLL, + wsi->user_space, (void *) &pa, 0); + + context->lws_lookup[wsi->sock] = wsi; + wsi->position_in_fds_table = context->fds_count; + context->fds[context->fds_count].fd = wsi->sock; + context->fds[context->fds_count].events = LWS_POLLIN; + + lws_plat_insert_socket_into_fds(context, wsi); + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_ADD_POLL_FD, + wsi->user_space, (void *) &pa, 0); + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_UNLOCK_POLL, + wsi->user_space, (void *)&pa, 0); + + return 0; +} + +int +remove_wsi_socket_from_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + int m; + struct libwebsocket_pollargs pa = { wsi->sock, 0, 0 }; + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); + + if (!--context->fds_count) { + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_LOCK_POLL, + wsi->user_space, (void *) &pa, 0); + goto do_ext; + } + + if (wsi->sock > context->max_fds) { + lwsl_err("Socket fd %d too high (%d)\n", + wsi->sock, context->max_fds); + return 1; + } + + lwsl_info("%s: wsi=%p, sock=%d, fds pos=%d\n", __func__, + wsi, wsi->sock, wsi->position_in_fds_table); + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_LOCK_POLL, + wsi->user_space, (void *)&pa, 0); + + m = wsi->position_in_fds_table; /* replace the contents for this */ + + /* have the last guy take up the vacant slot */ + context->fds[m] = context->fds[context->fds_count]; + + lws_plat_delete_socket_from_fds(context, wsi, m); + + /* + * end guy's fds_lookup entry remains unchanged + * (still same fd pointing to same wsi) + */ + /* end guy's "position in fds table" changed */ + context->lws_lookup[context->fds[context->fds_count].fd]-> + position_in_fds_table = m; + /* deletion guy's lws_lookup entry needs nuking */ + context->lws_lookup[wsi->sock] = NULL; + /* removed wsi has no position any more */ + wsi->position_in_fds_table = -1; + +do_ext: + /* remove also from external POLL support via protocol 0 */ + if (wsi->sock) { + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_DEL_POLL_FD, wsi->user_space, + (void *) &pa, 0); + } + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_UNLOCK_POLL, + wsi->user_space, (void *) &pa, 0); + return 0; +} + +int +lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or) +{ + struct libwebsocket_context *context; + int tid; + int sampled_tid; + struct libwebsocket_pollfd *pfd; + struct libwebsocket_pollargs pa; + + if (!wsi || !wsi->protocol || wsi->position_in_fds_table < 0) + return 1; + + context = wsi->protocol->owning_server; + if (!context) + return 1; + + pfd = &context->fds[wsi->position_in_fds_table]; + pa.fd = wsi->sock; + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 0); + + pa.prev_events = pfd->events; + pa.events = pfd->events = (pfd->events & ~_and) | _or; + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CHANGE_MODE_POLL_FD, + wsi->user_space, (void *) &pa, 0); + + /* + * if we changed something in this pollfd... + * ... and we're running in a different thread context + * than the service thread... + * ... and the service thread is waiting ... + * then cancel it to force a restart with our changed events + */ + if (pa.prev_events != pa.events) { + + if (lws_plat_change_pollfd(context, wsi, pfd)) { + lwsl_info("%s failed\n", __func__); + return 1; + } + + sampled_tid = context->service_tid; + if (sampled_tid) { + tid = context->protocols[0].callback(context, NULL, + LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); + if (tid != sampled_tid) + libwebsocket_cancel_service(context); + } + } + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *) &pa, 0); + + return 0; +} + + +/** + * libwebsocket_callback_on_writable() - Request a callback when this socket + * becomes able to be written to without + * blocking + * + * @context: libwebsockets context + * @wsi: Websocket connection instance to get callback for + */ + +LWS_VISIBLE int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ +#ifdef LWS_USE_HTTP2 + struct libwebsocket *network_wsi, *wsi2; + int already; + + lwsl_info("%s: %p\n", __func__, wsi); + + if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) + goto network_sock; + + if (wsi->u.http2.requested_POLLOUT) { + lwsl_info("already pending writable\n"); + return 1; + } + + if (wsi->u.http2.tx_credit <= 0) { + /* + * other side is not able to cope with us sending + * anything so no matter if we have POLLOUT on our side. + * + * Delay waiting for our POLLOUT until peer indicates he has + * space for more using tx window command in http2 layer + */ + lwsl_info("%s: %p: waiting_tx_credit (%d)\n", __func__, wsi, wsi->u.http2.tx_credit); + wsi->u.http2.waiting_tx_credit = 1; + return 0; + } + + network_wsi = lws_http2_get_network_wsi(wsi); + already = network_wsi->u.http2.requested_POLLOUT; + + /* mark everybody above him as requesting pollout */ + + wsi2 = wsi; + while (wsi2) { + wsi2->u.http2.requested_POLLOUT = 1; + lwsl_info("mark %p pending writable\n", wsi2); + wsi2 = wsi2->u.http2.parent_wsi; + } + + /* for network action, act only on the network wsi */ + + wsi = network_wsi; + if (already) + return 1; +network_sock: +#endif + + if (lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, NULL, 0)) + return 1; + + if (wsi->position_in_fds_table < 0) { + lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock); + return -1; + } + + if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) + return -1; + + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE); + + return 1; +} + +/** + * libwebsocket_callback_on_writable_all_protocol() - Request a callback for + * all connections using the given protocol when it + * becomes possible to write to each socket without + * blocking in turn. + * + * @protocol: Protocol whose connections will get callbacks + */ + +LWS_VISIBLE int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol) +{ + struct libwebsocket_context *context = protocol->owning_server; + int n; + struct libwebsocket *wsi; + + for (n = 0; n < context->fds_count; n++) { + wsi = context->lws_lookup[context->fds[n].fd]; + if (!wsi) + continue; + if (wsi->protocol == protocol) + libwebsocket_callback_on_writable(context, wsi); + } + + return 0; +} diff --git a/src/engine/external/libwebsockets/private-libwebsockets.h b/src/engine/external/libwebsockets/private-libwebsockets.h new file mode 100755 index 00000000..de43ec42 --- /dev/null +++ b/src/engine/external/libwebsockets/private-libwebsockets.h @@ -0,0 +1,1211 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 - 2013 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +/* System introspection configs */ +#ifdef CMAKE_BUILD +#include "lws_config.h" +#else +#if defined(WIN32) || defined(_WIN32) +#define inline __inline +#else /* not WIN32 */ +#include "config.h" + +#endif /* not WIN32 */ +#endif /* not CMAKE */ + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> +#include <limits.h> +#include <stdarg.h> + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#if defined(WIN32) || defined(_WIN32) +#define LWS_NO_DAEMONIZE +#define LWS_ERRNO WSAGetLastError() +#define LWS_EAGAIN WSAEWOULDBLOCK +#define LWS_EALREADY WSAEALREADY +#define LWS_EINPROGRESS WSAEINPROGRESS +#define LWS_EINTR WSAEINTR +#define LWS_EISCONN WSAEISCONN +#define LWS_EWOULDBLOCK WSAEWOULDBLOCK +#define LWS_POLLHUP (FD_CLOSE) +#define LWS_POLLIN (FD_READ | FD_ACCEPT) +#define LWS_POLLOUT (FD_WRITE) +#define MSG_NOSIGNAL 0 +#define SHUT_RDWR SD_BOTH +#define SOL_TCP IPPROTO_TCP + +#define compatible_close(fd) closesocket(fd) +#define compatible_file_close(fd) CloseHandle(fd) +#define compatible_file_seek_cur(fd, offset) SetFilePointer(fd, offset, NULL, FILE_CURRENT) +#define compatible_file_read(amount, fd, buf, len) {\ + DWORD _amount; \ + if (!ReadFile(fd, buf, len, &_amount, NULL)) \ + amount = -1; \ + else \ + amount = _amount; \ + } +#define lws_set_blocking_send(wsi) wsi->sock_send_blocking = TRUE +#include <winsock2.h> +#include <windows.h> +#include <tchar.h> +#ifdef HAVE_IN6ADDR_H +#include <in6addr.h> +#endif +#include <mstcpip.h> + +#ifndef __func__ +#define __func__ __FUNCTION__ +#endif + +#ifdef _WIN32_WCE +#define vsnprintf _vsnprintf +#endif + +#define LWS_INVALID_FILE INVALID_HANDLE_VALUE +#else /* not windows --> */ +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <signal.h> +#include <strings.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef LWS_BUILTIN_GETIFADDRS + #include <getifaddrs.h> +#else + #include <ifaddrs.h> +#endif +#if defined (__ANDROID__) +#include <syslog.h> +#else +#include <sys/syslog.h> +#endif +#include <sys/un.h> +#include <sys/socket.h> +#include <netdb.h> +#ifndef LWS_NO_FORK +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif +#endif +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <poll.h> +#ifdef LWS_USE_LIBEV +#include <ev.h> +#endif /* LWS_USE_LIBEV */ + +#include <sys/mman.h> +#include <sys/time.h> + +#define LWS_ERRNO errno +#define LWS_EAGAIN EAGAIN +#define LWS_EALREADY EALREADY +#define LWS_EINPROGRESS EINPROGRESS +#define LWS_EINTR EINTR +#define LWS_EISCONN EISCONN +#define LWS_EWOULDBLOCK EWOULDBLOCK +#define LWS_INVALID_FILE -1 +#define LWS_POLLHUP (POLLHUP|POLLERR) +#define LWS_POLLIN (POLLIN) +#define LWS_POLLOUT (POLLOUT) +#define compatible_close(fd) close(fd) +#define compatible_file_close(fd) close(fd) +#define compatible_file_seek_cur(fd, offset) lseek(fd, offset, SEEK_CUR) +#define compatible_file_read(amount, fd, buf, len) \ + amount = read(fd, buf, len); +#define lws_set_blocking_send(wsi) +#endif + +#ifndef HAVE_BZERO +#ifndef bzero +#define bzero(b, len) (memset((b), '\0', (len)), (void) 0) +#endif +#endif + +#ifndef HAVE_STRERROR +#define strerror(x) "" +#endif + +#ifdef LWS_OPENSSL_SUPPORT +#ifdef USE_CYASSL +#include <cyassl/openssl/ssl.h> +#include <cyassl/error-ssl.h> +#else +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/md5.h> +#include <openssl/sha.h> +#endif /* not USE_CYASSL */ +#endif + +#include "libwebsockets.h" + +#if defined(WIN32) || defined(_WIN32) + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 /* to show byte order (taken from gcc) */ +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif +typedef unsigned __int64 u_int64_t; + +#undef __P +#ifndef __P +#if __STDC__ +#define __P(protos) protos +#else +#define __P(protos) () +#endif +#endif + +#else + +#include <sys/stat.h> +#include <sys/cdefs.h> +#include <sys/time.h> + +#if defined(__APPLE__) +#include <machine/endian.h> +#elif defined(__FreeBSD__) +#include <sys/endian.h> +#elif defined(__linux__) +#include <endian.h> +#endif + +#include <stddef.h> + +#ifndef container_of +#define container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M))) +#endif + +#if defined(__QNX__) + #include <gulliver.h> + #if defined(__LITTLEENDIAN__) + #define BYTE_ORDER __LITTLEENDIAN__ + #define LITTLE_ENDIAN __LITTLEENDIAN__ + #define BIG_ENDIAN 4321 /* to show byte order (taken from gcc); for suppres warning that BIG_ENDIAN is not defined. */ + #endif + #if defined(__BIGENDIAN__) + #define BYTE_ORDER __BIGENDIAN__ + #define LITTLE_ENDIAN 1234 /* to show byte order (taken from gcc); for suppres warning that LITTLE_ENDIAN is not defined. */ + #define BIG_ENDIAN __BIGENDIAN__ + #endif +#endif + +#if !defined(BYTE_ORDER) +# define BYTE_ORDER __BYTE_ORDER +#endif +#if !defined(LITTLE_ENDIAN) +# define LITTLE_ENDIAN __LITTLE_ENDIAN +#endif +#if !defined(BIG_ENDIAN) +# define BIG_ENDIAN __BIG_ENDIAN +#endif + +#endif + +/* + * Mac OSX as well as iOS do not define the MSG_NOSIGNAL flag, + * but happily have something equivalent in the SO_NOSIGPIPE flag. + */ +#ifdef __APPLE__ +#define MSG_NOSIGNAL SO_NOSIGPIPE +#endif + +#ifndef LWS_MAX_HEADER_LEN +#define LWS_MAX_HEADER_LEN 1024 +#endif +#ifndef LWS_MAX_PROTOCOLS +#define LWS_MAX_PROTOCOLS 5 +#endif +#ifndef LWS_MAX_EXTENSIONS_ACTIVE +#define LWS_MAX_EXTENSIONS_ACTIVE 3 +#endif +#ifndef SPEC_LATEST_SUPPORTED +#define SPEC_LATEST_SUPPORTED 13 +#endif +#ifndef AWAITING_TIMEOUT +#define AWAITING_TIMEOUT 5 +#endif +#ifndef CIPHERS_LIST_STRING +#define CIPHERS_LIST_STRING "DEFAULT" +#endif +#ifndef LWS_SOMAXCONN +#define LWS_SOMAXCONN SOMAXCONN +#endif + +#define MAX_WEBSOCKET_04_KEY_LEN 128 +#define LWS_MAX_SOCKET_IO_BUF 4096 + +#ifndef SYSTEM_RANDOM_FILEPATH +#define SYSTEM_RANDOM_FILEPATH "/dev/urandom" +#endif +#ifndef LWS_MAX_ZLIB_CONN_BUFFER +#define LWS_MAX_ZLIB_CONN_BUFFER (64 * 1024) +#endif + +/* + * if not in a connection storm, check for incoming + * connections this many normal connection services + */ +#define LWS_LISTEN_SERVICE_MODULO 10 + +enum lws_websocket_opcodes_07 { + LWS_WS_OPCODE_07__CONTINUATION = 0, + LWS_WS_OPCODE_07__TEXT_FRAME = 1, + LWS_WS_OPCODE_07__BINARY_FRAME = 2, + + LWS_WS_OPCODE_07__NOSPEC__MUX = 7, + + /* control extensions 8+ */ + + LWS_WS_OPCODE_07__CLOSE = 8, + LWS_WS_OPCODE_07__PING = 9, + LWS_WS_OPCODE_07__PONG = 0xa, +}; + + +enum lws_connection_states { + WSI_STATE_HTTP, + WSI_STATE_HTTP_ISSUING_FILE, + WSI_STATE_HTTP_HEADERS, + WSI_STATE_HTTP_BODY, + WSI_STATE_DEAD_SOCKET, + WSI_STATE_ESTABLISHED, + WSI_STATE_CLIENT_UNCONNECTED, + WSI_STATE_RETURNED_CLOSE_ALREADY, + WSI_STATE_AWAITING_CLOSE_ACK, + WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE, + + WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE, + WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS, + WSI_STATE_HTTP2_ESTABLISHED, +}; + +enum http_version { + HTTP_VERSION_1_0, + HTTP_VERSION_1_1, +}; + +enum http_connection_type { + HTTP_CONNECTION_CLOSE, + HTTP_CONNECTION_KEEP_ALIVE +}; + +enum lws_pending_protocol_send { + LWS_PPS_NONE, + LWS_PPS_HTTP2_MY_SETTINGS, + LWS_PPS_HTTP2_ACK_SETTINGS, + LWS_PPS_HTTP2_PONG, +}; + +enum lws_rx_parse_state { + LWS_RXPS_NEW, + + LWS_RXPS_04_MASK_NONCE_1, + LWS_RXPS_04_MASK_NONCE_2, + LWS_RXPS_04_MASK_NONCE_3, + + LWS_RXPS_04_FRAME_HDR_1, + LWS_RXPS_04_FRAME_HDR_LEN, + LWS_RXPS_04_FRAME_HDR_LEN16_2, + LWS_RXPS_04_FRAME_HDR_LEN16_1, + LWS_RXPS_04_FRAME_HDR_LEN64_8, + LWS_RXPS_04_FRAME_HDR_LEN64_7, + LWS_RXPS_04_FRAME_HDR_LEN64_6, + LWS_RXPS_04_FRAME_HDR_LEN64_5, + LWS_RXPS_04_FRAME_HDR_LEN64_4, + LWS_RXPS_04_FRAME_HDR_LEN64_3, + LWS_RXPS_04_FRAME_HDR_LEN64_2, + LWS_RXPS_04_FRAME_HDR_LEN64_1, + + LWS_RXPS_07_COLLECT_FRAME_KEY_1, + LWS_RXPS_07_COLLECT_FRAME_KEY_2, + LWS_RXPS_07_COLLECT_FRAME_KEY_3, + LWS_RXPS_07_COLLECT_FRAME_KEY_4, + + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED +}; + + +enum connection_mode { + LWS_CONNMODE_HTTP_SERVING, + LWS_CONNMODE_HTTP_SERVING_ACCEPTED, /* actual HTTP service going on */ + LWS_CONNMODE_PRE_WS_SERVING_ACCEPT, + + LWS_CONNMODE_WS_SERVING, + LWS_CONNMODE_WS_CLIENT, + + LWS_CONNMODE_HTTP2_SERVING, + + /* transient, ssl delay hiding */ + LWS_CONNMODE_SSL_ACK_PENDING, + + /* transient modes */ + LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT, + LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY, + LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE, + LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2, + LWS_CONNMODE_WS_CLIENT_WAITING_SSL, + LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY, + LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT, + LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD, + + /* special internal types */ + LWS_CONNMODE_SERVER_LISTENER, +}; + +enum { + LWS_RXFLOW_ALLOW = (1 << 0), + LWS_RXFLOW_PENDING_CHANGE = (1 << 1), +}; + +struct libwebsocket_protocols; +struct libwebsocket; + +#ifdef LWS_USE_LIBEV +struct lws_io_watcher { + struct ev_io watcher; + struct libwebsocket_context* context; +}; + +struct lws_signal_watcher { + struct ev_signal watcher; + struct libwebsocket_context* context; +}; +#endif /* LWS_USE_LIBEV */ + +struct libwebsocket_context { +#ifdef _WIN32 + WSAEVENT *events; +#endif + struct libwebsocket_pollfd *fds; + struct libwebsocket **lws_lookup; /* fd to wsi */ + int fds_count; +#ifdef LWS_USE_LIBEV + struct ev_loop* io_loop; + struct lws_io_watcher w_accept; + struct lws_signal_watcher w_sigint; +#endif /* LWS_USE_LIBEV */ + int max_fds; + int listen_port; + const char *iface; + char http_proxy_address[128]; + char canonical_hostname[128]; + unsigned int http_proxy_port; + unsigned int options; + time_t last_timeout_check_s; + + /* + * usable by anything in the service code, but only if the scope + * does not last longer than the service action (since next service + * of any socket can likewise use it and overwrite) + */ + unsigned char service_buffer[LWS_MAX_SOCKET_IO_BUF]; + + int started_with_parent; + + int fd_random; + int listen_service_modulo; + int listen_service_count; + int listen_service_fd; + int listen_service_extraseen; + + /* + * set to the Thread ID that's doing the service loop just before entry + * to poll indicates service thread likely idling in poll() + * volatile because other threads may check it as part of processing + * for pollfd event change. + */ + volatile int service_tid; +#ifndef _WIN32 + int dummy_pipe_fds[2]; +#endif + + int ka_time; + int ka_probes; + int ka_interval; + +#ifdef LWS_LATENCY + unsigned long worst_latency; + char worst_latency_info[256]; +#endif + +#ifdef LWS_OPENSSL_SUPPORT + int use_ssl; + int allow_non_ssl_on_ssl_port; + unsigned int user_supplied_ssl_ctx:1; + SSL_CTX *ssl_ctx; + SSL_CTX *ssl_client_ctx; + unsigned int ssl_flag_buffered_reads:1; +#endif + struct libwebsocket_protocols *protocols; + int count_protocols; +#ifndef LWS_NO_EXTENSIONS + struct libwebsocket_extension *extensions; +#endif + struct lws_token_limits *token_limits; + void *user_space; +}; + +enum { + LWS_EV_READ = (1 << 0), + LWS_EV_WRITE = (1 << 1), + LWS_EV_START = (1 << 2), + LWS_EV_STOP = (1 << 3), +}; + +#ifdef LWS_USE_LIBEV +#define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV) +LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info); +LWS_EXTERN void +lws_libev_accept(struct libwebsocket_context *context, + struct libwebsocket *new_wsi, int accept_fd); +LWS_EXTERN void +lws_libev_io(struct libwebsocket_context *context, + struct libwebsocket *wsi, int flags); +LWS_EXTERN int +lws_libev_init_fd_table(struct libwebsocket_context *context); +LWS_EXTERN void +lws_libev_run(struct libwebsocket_context *context); +#else +#define LWS_LIBEV_ENABLED(context) (0) +#define lws_feature_status_libev(_a) \ + lwsl_notice("libev support not compiled in\n") +#define lws_libev_accept(_a, _b, _c) ((void) 0) +#define lws_libev_io(_a, _b, _c) ((void) 0) +#define lws_libev_init_fd_table(_a) (0) +#define lws_libev_run(_a) ((void) 0) +#endif + +#ifdef LWS_USE_IPV6 +#define LWS_IPV6_ENABLED(context) (!(context->options & LWS_SERVER_OPTION_DISABLE_IPV6)) +#else +#define LWS_IPV6_ENABLED(context) (0) +#endif + +enum uri_path_states { + URIPS_IDLE, + URIPS_SEEN_SLASH, + URIPS_SEEN_SLASH_DOT, + URIPS_SEEN_SLASH_DOT_DOT, + URIPS_ARGUMENTS, +}; + +enum uri_esc_states { + URIES_IDLE, + URIES_SEEN_PERCENT, + URIES_SEEN_PERCENT_H1, +}; + +/* + * This is totally opaque to code using the library. It's exported as a + * forward-reference pointer-only declaration; the user can use the pointer with + * other APIs to get information out of it. + */ + +struct lws_fragments { + unsigned short offset; + unsigned short len; + unsigned char next_frag_index; +}; + +/* notice that these union members: + * + * hdr + * http + * http2 + * + * all have a pointer to allocated_headers struct as their first member. + * + * It means for allocated_headers access, the three union paths can all be + * used interchangably to access the same data + */ + +struct allocated_headers { + unsigned short next_frag_index; + unsigned short pos; + unsigned char frag_index[WSI_TOKEN_COUNT]; + struct lws_fragments frags[WSI_TOKEN_COUNT * 2]; + char data[LWS_MAX_HEADER_LEN]; +#ifndef LWS_NO_CLIENT + char initial_handshake_hash_base64[30]; + unsigned short c_port; +#endif +}; + +struct _lws_http_mode_related { + /* MUST be first in struct */ + struct allocated_headers *ah; /* mirroring _lws_header_related */ +#if defined(WIN32) || defined(_WIN32) + HANDLE fd; +#else + int fd; +#endif + unsigned long filepos; + unsigned long filelen; + + enum http_version request_version; + enum http_connection_type connection_type; + int content_length; + int content_remain; +}; + + +#ifdef LWS_USE_HTTP2 + +enum lws_http2_settings { + LWS_HTTP2_SETTINGS__HEADER_TABLE_SIZE = 1, + LWS_HTTP2_SETTINGS__ENABLE_PUSH, + LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS, + LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE, + LWS_HTTP2_SETTINGS__MAX_FRAME_SIZE, + LWS_HTTP2_SETTINGS__MAX_HEADER_LIST_SIZE, + + LWS_HTTP2_SETTINGS__COUNT /* always last */ +}; + +enum lws_http2_wellknown_frame_types { + LWS_HTTP2_FRAME_TYPE_DATA, + LWS_HTTP2_FRAME_TYPE_HEADERS, + LWS_HTTP2_FRAME_TYPE_PRIORITY, + LWS_HTTP2_FRAME_TYPE_RST_STREAM, + LWS_HTTP2_FRAME_TYPE_SETTINGS, + LWS_HTTP2_FRAME_TYPE_PUSH_PROMISE, + LWS_HTTP2_FRAME_TYPE_PING, + LWS_HTTP2_FRAME_TYPE_GOAWAY, + LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE, + LWS_HTTP2_FRAME_TYPE_CONTINUATION, + + LWS_HTTP2_FRAME_TYPE_COUNT /* always last */ +}; + +enum lws_http2_flags { + LWS_HTTP2_FLAG_END_STREAM = 1, + LWS_HTTP2_FLAG_END_HEADERS = 4, + LWS_HTTP2_FLAG_PADDED = 8, + LWS_HTTP2_FLAG_PRIORITY = 0x20, + + LWS_HTTP2_FLAG_SETTINGS_ACK = 1, +}; + +#define LWS_HTTP2_STREAM_ID_MASTER 0 +#define LWS_HTTP2_FRAME_HEADER_LENGTH 9 +#define LWS_HTTP2_SETTINGS_LENGTH 6 + +struct http2_settings { + unsigned int setting[LWS_HTTP2_SETTINGS__COUNT]; +}; + +enum http2_hpack_state { + + /* optional before first header block */ + HPKS_OPT_PADDING, + HKPS_OPT_E_DEPENDENCY, + HKPS_OPT_WEIGHT, + + /* header block */ + HPKS_TYPE, + + HPKS_IDX_EXT, + + HPKS_HLEN, + HPKS_HLEN_EXT, + + HPKS_DATA, + + /* optional after last header block */ + HKPS_OPT_DISCARD_PADDING, +}; + +enum http2_hpack_type { + HPKT_INDEXED_HDR_7, + HPKT_INDEXED_HDR_6_VALUE_INCR, + HPKT_LITERAL_HDR_VALUE_INCR, + HPKT_INDEXED_HDR_4_VALUE, + HPKT_LITERAL_HDR_VALUE, + HPKT_SIZE_5 +}; + +struct hpack_dt_entry { + int token; /* additions that don't map to a token are ignored */ + int arg_offset; + int arg_len; +}; + +struct hpack_dynamic_table { + struct hpack_dt_entry *entries; + char *args; + int pos; + int next; + int num_entries; + int args_length; +}; + +struct _lws_http2_related { + /* + * having this first lets us also re-use all HTTP union code + * and in turn, http_mode_related has allocated headers in right + * place so we can use the header apis on the wsi directly still + */ + struct _lws_http_mode_related http; /* MUST BE FIRST IN STRUCT */ + + struct http2_settings my_settings; + struct http2_settings peer_settings; + + struct libwebsocket *parent_wsi; + struct libwebsocket *next_child_wsi; + + struct hpack_dynamic_table *hpack_dyn_table; + + unsigned int count; + + /* frame */ + unsigned int length; + unsigned int stream_id; + struct libwebsocket *stream_wsi; + unsigned char type; + unsigned char flags; + unsigned char frame_state; + unsigned char padding; + + unsigned char ping_payload[8]; + + unsigned short round_robin_POLLOUT; + unsigned short count_POLLOUT_children; + + unsigned int END_STREAM:1; + unsigned int END_HEADERS:1; + unsigned int send_END_STREAM:1; + unsigned int GOING_AWAY; + unsigned int requested_POLLOUT:1; + unsigned int waiting_tx_credit:1; + + /* hpack */ + enum http2_hpack_state hpack; + enum http2_hpack_type hpack_type; + unsigned int header_index; + unsigned int hpack_len; + unsigned short hpack_pos; + unsigned char hpack_m; + unsigned int hpack_e_dep; + unsigned int huff:1; + unsigned int value:1; + + /* negative credit is mandated by the spec */ + int tx_credit; + unsigned int my_stream_id; + unsigned int child_count; + int my_priority; + unsigned char initialized; + unsigned char one_setting[LWS_HTTP2_SETTINGS_LENGTH]; +}; + +#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->u.http2.parent_wsi) + +#endif + +struct _lws_header_related { + /* MUST be first in struct */ + struct allocated_headers *ah; + short lextable_pos; + unsigned short current_token_limit; + unsigned char parser_state; /* enum lws_token_indexes */ + enum uri_path_states ups; + enum uri_esc_states ues; + char esc_stash; +}; + +struct _lws_websocket_related { + char *rx_user_buffer; + int rx_user_buffer_head; + unsigned char frame_masking_nonce_04[4]; + unsigned char frame_mask_index; + size_t rx_packet_length; + unsigned char opcode; + unsigned int final:1; + unsigned char rsv; + unsigned int frame_is_binary:1; + unsigned int all_zero_nonce:1; + short close_reason; /* enum lws_close_status */ + + unsigned int this_frame_masked:1; + unsigned int inside_frame:1; /* next write will be more of frame */ + unsigned int clean_buffer:1; /* buffer not rewritten by extension */ + + unsigned char *ping_payload_buf; /* non-NULL if malloc'd */ + unsigned int ping_payload_alloc; /* length malloc'd */ + unsigned int ping_payload_len; /* nonzero if PONG pending */ +}; + +struct libwebsocket { + + /* lifetime members */ + +#ifdef LWS_USE_LIBEV + struct lws_io_watcher w_read; + struct lws_io_watcher w_write; +#endif /* LWS_USE_LIBEV */ + const struct libwebsocket_protocols *protocol; +#ifndef LWS_NO_EXTENSIONS + struct libwebsocket_extension * + active_extensions[LWS_MAX_EXTENSIONS_ACTIVE]; + void *active_extensions_user[LWS_MAX_EXTENSIONS_ACTIVE]; + unsigned char count_active_extensions; + unsigned int extension_data_pending:1; +#endif + unsigned char ietf_spec_revision; + enum lws_pending_protocol_send pps; + + char mode; /* enum connection_mode */ + char state; /* enum lws_connection_states */ + char lws_rx_parse_state; /* enum lws_rx_parse_state */ + char rx_frame_type; /* enum libwebsocket_write_protocol */ + + unsigned int hdr_parsing_completed:1; + unsigned int user_space_externally_allocated:1; + unsigned int socket_is_permanently_unusable:1; + + char pending_timeout; /* enum pending_timeout */ + time_t pending_timeout_limit; + + int sock; + int position_in_fds_table; +#ifdef LWS_LATENCY + unsigned long action_start; + unsigned long latency_start; +#endif + /* rxflow handling */ + unsigned char *rxflow_buffer; + int rxflow_len; + int rxflow_pos; + unsigned int rxflow_change_to:2; + + /* truncated send handling */ + unsigned char *truncated_send_malloc; /* non-NULL means buffering in progress */ + unsigned int truncated_send_allocation; /* size of malloc */ + unsigned int truncated_send_offset; /* where we are in terms of spilling */ + unsigned int truncated_send_len; /* how much is buffered */ + + void *user_space; + + /* members with mutually exclusive lifetimes are unionized */ + + union u { + struct _lws_http_mode_related http; +#ifdef LWS_USE_HTTP2 + struct _lws_http2_related http2; +#endif + struct _lws_header_related hdr; + struct _lws_websocket_related ws; + } u; + +#ifdef LWS_OPENSSL_SUPPORT + SSL *ssl; + BIO *client_bio; + unsigned int use_ssl:2; + unsigned int buffered_reads_pending:1; + unsigned int upgraded:1; +#endif + +#ifdef _WIN32 + BOOL sock_send_blocking; +#endif +}; + +LWS_EXTERN int log_level; + +LWS_EXTERN void +libwebsocket_close_and_free_session(struct libwebsocket_context *context, + struct libwebsocket *wsi, enum lws_close_status); + +LWS_EXTERN int +remove_wsi_socket_from_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi); +LWS_EXTERN int +lws_rxflow_cache(struct libwebsocket *wsi, unsigned char *buf, int n, int len); + +#ifndef LWS_LATENCY +static inline void lws_latency(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *action, + int ret, int completion) { do { } while (0); } +static inline void lws_latency_pre(struct libwebsocket_context *context, + struct libwebsocket *wsi) { do { } while (0); } +#else +#define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0) +extern void +lws_latency(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *action, + int ret, int completion); +#endif + +LWS_EXTERN void lws_set_protocol_write_pending(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum lws_pending_protocol_send pend); +LWS_EXTERN int +libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c); + +LWS_EXTERN int +libwebsocket_parse(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char c); + +LWS_EXTERN int +lws_http_action(struct libwebsocket_context *context, struct libwebsocket *wsi); + +LWS_EXTERN int +lws_b64_selftest(void); + +LWS_EXTERN struct libwebsocket * +wsi_from_fd(struct libwebsocket_context *context, int fd); + +LWS_EXTERN int +insert_wsi_socket_into_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_EXTERN int +lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len); + + +LWS_EXTERN int +libwebsocket_service_timeout_check(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int sec); + +LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_2(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_EXTERN struct libwebsocket * +libwebsocket_create_new_server_wsi(struct libwebsocket_context *context); + +LWS_EXTERN char * +libwebsockets_generate_client_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi, char *pkt); + +LWS_EXTERN int +lws_handle_POLLOUT_event(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd); + +/* + * EXTENSIONS + */ + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE void +lws_context_init_extensions(struct lws_context_creation_info *info, + struct libwebsocket_context *context); +LWS_EXTERN int +lws_any_extension_handled(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons r, + void *v, size_t len); + +LWS_EXTERN int +lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason, + void *buf, int len); +LWS_EXTERN int +lws_ext_callback_for_each_extension_type( + struct libwebsocket_context *context, struct libwebsocket *wsi, + int reason, void *arg, int len); +#else +#define lws_any_extension_handled(_a, _b, _c, _d, _e) (0) +#define lws_ext_callback_for_each_active(_a, _b, _c, _d) (0) +#define lws_ext_callback_for_each_extension_type(_a, _b, _c, _d, _e) (0) +#define lws_issue_raw_ext_access lws_issue_raw +#define lws_context_init_extensions(_a, _b) +#endif + +LWS_EXTERN int +lws_client_interpret_server_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c); + +LWS_EXTERN int +lws_issue_raw_ext_access(struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +LWS_EXTERN int +_libwebsocket_rx_flow_control(struct libwebsocket *wsi); + +LWS_EXTERN void +lws_union_transition(struct libwebsocket *wsi, enum connection_mode mode); + +LWS_EXTERN int +user_callback_handle_rxflow(callback_function, + struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); +#ifdef LWS_USE_HTTP2 +LWS_EXTERN struct libwebsocket *lws_http2_get_network_wsi(struct libwebsocket *wsi); +struct libwebsocket * lws_http2_get_nth_child(struct libwebsocket *wsi, int n); +LWS_EXTERN int +lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len); +LWS_EXTERN void lws_http2_init(struct http2_settings *settings); +LWS_EXTERN int +lws_http2_parser(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char c); +LWS_EXTERN int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsocket *wsi); +LWS_EXTERN int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf); +LWS_EXTERN struct libwebsocket * +lws_http2_wsi_from_id(struct libwebsocket *wsi, unsigned int sid); +LWS_EXTERN int lws_hpack_interpret(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char c); +LWS_EXTERN int +lws_add_http2_header_by_name(struct libwebsocket_context *context, + struct libwebsocket *wsi, + const unsigned char *name, + const unsigned char *value, + int length, + unsigned char **p, + unsigned char *end); +LWS_EXTERN int +lws_add_http2_header_by_token(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum lws_token_indexes token, + const unsigned char *value, + int length, + unsigned char **p, + unsigned char *end); +LWS_EXTERN int +lws_add_http2_header_status(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned int code, + unsigned char **p, + unsigned char *end); +LWS_EXTERN +void lws_http2_configure_if_upgraded(struct libwebsocket *wsi); +#else +#define lws_http2_configure_if_upgraded(x) +#endif + +LWS_EXTERN int +lws_plat_set_socket_options(struct libwebsocket_context *context, int fd); + +LWS_EXTERN int +lws_allocate_header_table(struct libwebsocket *wsi); + +LWS_EXTERN int +lws_free_header_table(struct libwebsocket *wsi); + +LWS_EXTERN char * +lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_EXTERN int +lws_hdr_simple_create(struct libwebsocket *wsi, + enum lws_token_indexes h, const char *s); + +LWS_EXTERN int +libwebsocket_ensure_user_space(struct libwebsocket *wsi); + +LWS_EXTERN int +lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or); + +#ifndef LWS_NO_SERVER +int lws_context_init_server(struct lws_context_creation_info *info, + struct libwebsocket_context *context); +LWS_EXTERN int handshake_0405(struct libwebsocket_context *context, + struct libwebsocket *wsi); +LWS_EXTERN int +libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, + unsigned char *buf, size_t len); +LWS_EXTERN void +lws_server_get_canonical_hostname(struct libwebsocket_context *context, + struct lws_context_creation_info *info); +#else +#define lws_context_init_server(_a, _b) (0) +#define libwebsocket_interpret_incoming_packet(_a, _b, _c) (0) +#define lws_server_get_canonical_hostname(_a, _b) +#endif + +#ifndef LWS_NO_DAEMONIZE +LWS_EXTERN int get_daemonize_pid(); +#else +#define get_daemonize_pid() (0) +#endif + +LWS_EXTERN int interface_to_sa(struct libwebsocket_context *context, + const char *ifname, struct sockaddr_in *addr, size_t addrlen); + +LWS_EXTERN void lwsl_emit_stderr(int level, const char *line); + +#ifdef _WIN32 +LWS_EXTERN HANDLE lws_plat_open_file(const char* filename, unsigned long* filelen); +#else +LWS_EXTERN int lws_plat_open_file(const char* filename, unsigned long* filelen); +#endif + +enum lws_ssl_capable_status { + LWS_SSL_CAPABLE_ERROR = -1, + LWS_SSL_CAPABLE_MORE_SERVICE = -2, +}; + +#ifndef LWS_OPENSSL_SUPPORT +#define LWS_SSL_ENABLED(context) (0) +#define lws_context_init_server_ssl(_a, _b) (0) +#define lws_ssl_destroy(_a) +#define lws_context_init_http2_ssl(_a) +#define lws_ssl_capable_read lws_ssl_capable_read_no_ssl +#define lws_ssl_capable_write lws_ssl_capable_write_no_ssl +#define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0) +#define lws_ssl_close(_a) (0) +#define lws_ssl_context_destroy(_a) +#else +#define LWS_SSL_ENABLED(context) (context->use_ssl) +LWS_EXTERN int openssl_websocket_private_data_index; +LWS_EXTERN int +lws_ssl_capable_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char *buf, int len); + +LWS_EXTERN int +lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len); +LWS_EXTERN int +lws_server_socket_service_ssl(struct libwebsocket_context *context, + struct libwebsocket **wsi, struct libwebsocket *new_wsi, + int accept_fd, struct libwebsocket_pollfd *pollfd); +LWS_EXTERN int +lws_ssl_close(struct libwebsocket *wsi); +LWS_EXTERN void +lws_ssl_context_destroy(struct libwebsocket_context *context); +#ifndef LWS_NO_SERVER +LWS_EXTERN int +lws_context_init_server_ssl(struct lws_context_creation_info *info, + struct libwebsocket_context *context); +#else +#define lws_context_init_server_ssl(_a, _b) (0) +#endif +LWS_EXTERN void +lws_ssl_destroy(struct libwebsocket_context *context); + +/* HTTP2-related */ + +#ifdef LWS_USE_HTTP2 +LWS_EXTERN void +lws_context_init_http2_ssl(struct libwebsocket_context *context); +#else +#define lws_context_init_http2_ssl(_a) +#endif +#endif + +LWS_EXTERN int +lws_ssl_capable_read_no_ssl(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char *buf, int len); + +LWS_EXTERN int +lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len); + +#ifndef LWS_NO_CLIENT + LWS_EXTERN int lws_client_socket_service( + struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd); +#ifdef LWS_OPENSSL_SUPPORT + LWS_EXTERN int lws_context_init_client_ssl(struct lws_context_creation_info *info, + struct libwebsocket_context *context); +#else + #define lws_context_init_client_ssl(_a, _b) (0) +#endif + LWS_EXTERN int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len); + LWS_EXTERN void + libwebsockets_decode_ssl_error(void); +#else +#define lws_context_init_client_ssl(_a, _b) (0) +#define lws_handshake_client(_a, _b, _c) (0) +#endif +#ifndef LWS_NO_SERVER + LWS_EXTERN int lws_server_socket_service( + struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd); + LWS_EXTERN int _libwebsocket_rx_flow_control(struct libwebsocket *wsi); + LWS_EXTERN int lws_handshake_server(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char **buf, size_t len); +#else +#define lws_server_socket_service(_a, _b, _c) (0) +#define _libwebsocket_rx_flow_control(_a) (0) +#define lws_handshake_server(_a, _b, _c, _d) (0) +#endif + +/* + * custom allocator + */ +LWS_EXTERN void* +lws_realloc(void *ptr, size_t size); + +LWS_EXTERN void* +lws_zalloc(size_t size); + +#define lws_malloc(S) lws_realloc(NULL, S) +#define lws_free(P) lws_realloc(P, 0) +#define lws_free2(P) do { lws_realloc(P, 0); (P) = NULL; } while(0) + +/* + * lws_plat_ + */ +LWS_EXTERN void +lws_plat_delete_socket_from_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi, int m); +LWS_EXTERN void +lws_plat_insert_socket_into_fds(struct libwebsocket_context *context, + struct libwebsocket *wsi); +LWS_EXTERN void +lws_plat_service_periodic(struct libwebsocket_context *context); + +LWS_EXTERN int +lws_plat_change_pollfd(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd); +LWS_EXTERN int +lws_plat_context_early_init(void); +LWS_EXTERN void +lws_plat_context_early_destroy(struct libwebsocket_context *context); +LWS_EXTERN void +lws_plat_context_late_destroy(struct libwebsocket_context *context); +LWS_EXTERN int +lws_poll_listen_fd(struct libwebsocket_pollfd *fd); +LWS_EXTERN int +lws_plat_service(struct libwebsocket_context *context, int timeout_ms); +LWS_EXTERN int +lws_plat_init_fd_tables(struct libwebsocket_context *context); +LWS_EXTERN void +lws_plat_drop_app_privileges(struct lws_context_creation_info *info); +LWS_EXTERN unsigned long long +time_in_microseconds(void); +LWS_EXTERN const char * +lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt); diff --git a/src/engine/external/libwebsockets/server-handshake.c b/src/engine/external/libwebsockets/server-handshake.c new file mode 100644 index 00000000..b4641d1b --- /dev/null +++ b/src/engine/external/libwebsockets/server-handshake.c @@ -0,0 +1,274 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); } +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE int +lws_extension_server_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi, char **p) +{ + int n; + char *c; + char ext_name[128]; + struct libwebsocket_extension *ext; + int ext_count = 0; + int more = 1; + + /* + * Figure out which extensions the client has that we want to + * enable on this connection, and give him back the list + */ + + if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) + return 0; + + /* + * break down the list of client extensions + * and go through them + */ + + if (lws_hdr_copy(wsi, (char *)context->service_buffer, + sizeof(context->service_buffer), + WSI_TOKEN_EXTENSIONS) < 0) + return 1; + + c = (char *)context->service_buffer; + lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c); + wsi->count_active_extensions = 0; + n = 0; + while (more) { + + if (*c && (*c != ',' && *c != ' ' && *c != '\t')) { + ext_name[n] = *c++; + if (n < sizeof(ext_name) - 1) + n++; + continue; + } + ext_name[n] = '\0'; + if (!*c) + more = 0; + else { + c++; + if (!n) + continue; + } + + /* check a client's extension against our support */ + + ext = wsi->protocol->owning_server->extensions; + + while (ext && ext->callback) { + + if (strcmp(ext_name, ext->name)) { + ext++; + continue; + } + + /* + * oh, we do support this one he + * asked for... but let's ask user + * code if it's OK to apply it on this + * particular connection + protocol + */ + + n = wsi->protocol->owning_server-> + protocols[0].callback( + wsi->protocol->owning_server, + wsi, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + wsi->user_space, ext_name, 0); + + /* + * zero return from callback means + * go ahead and allow the extension, + * it's what we get if the callback is + * unhandled + */ + + if (n) { + ext++; + continue; + } + + /* apply it */ + + if (ext_count) + *(*p)++ = ','; + else + LWS_CPYAPP(*p, + "\x0d\x0aSec-WebSocket-Extensions: "); + *p += sprintf(*p, "%s", ext_name); + ext_count++; + + /* instantiate the extension on this conn */ + + wsi->active_extensions_user[ + wsi->count_active_extensions] = + lws_zalloc(ext->per_session_data_size); + if (wsi->active_extensions_user[ + wsi->count_active_extensions] == NULL) { + lwsl_err("Out of mem\n"); + return 1; + } + + wsi->active_extensions[ + wsi->count_active_extensions] = ext; + + /* allow him to construct his context */ + + ext->callback(wsi->protocol->owning_server, + ext, wsi, + LWS_EXT_CALLBACK_CONSTRUCT, + wsi->active_extensions_user[ + wsi->count_active_extensions], NULL, 0); + + wsi->count_active_extensions++; + lwsl_parser("count_active_extensions <- %d\n", + wsi->count_active_extensions); + + ext++; + } + + n = 0; + } + + return 0; +} +#endif +int +handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) +{ + unsigned char hash[20]; + int n; + char *response; + char *p; + int accept_len; + + if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) || + !lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) { + lwsl_parser("handshake_04 missing pieces\n"); + /* completed header processing, but missing some bits */ + goto bail; + } + + if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >= + MAX_WEBSOCKET_04_KEY_LEN) { + lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN); + goto bail; + } + + /* + * since key length is restricted above (currently 128), cannot + * overflow + */ + n = sprintf((char *)context->service_buffer, + "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY)); + + libwebsockets_SHA1(context->service_buffer, n, hash); + + accept_len = lws_b64_encode_string((char *)hash, 20, + (char *)context->service_buffer, + sizeof(context->service_buffer)); + if (accept_len < 0) { + lwsl_warn("Base64 encoded hash too long\n"); + goto bail; + } + + /* allocate the per-connection user memory (if any) */ + if (libwebsocket_ensure_user_space(wsi)) + goto bail; + + /* create the response packet */ + + /* make a buffer big enough for everything */ + + response = (char *)context->service_buffer + MAX_WEBSOCKET_04_KEY_LEN + LWS_SEND_BUFFER_PRE_PADDING; + p = response; + LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a" + "Upgrade: WebSocket\x0d\x0a" + "Connection: Upgrade\x0d\x0a" + "Sec-WebSocket-Accept: "); + strcpy(p, (char *)context->service_buffer); + p += accept_len; + + if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) { + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); + n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL); + if (n < 0) + goto bail; + p += n; + } + +#ifndef LWS_NO_EXTENSIONS + /* + * Figure out which extensions the client has that we want to + * enable on this connection, and give him back the list + */ + if (lws_extension_server_handshake(context, wsi, &p)) + goto bail; +#endif + /* end of response packet */ + + LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); + + if (!lws_any_extension_handled(context, wsi, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + response, p - response)) { + + /* okay send the handshake response accepting the connection */ + + lwsl_parser("issuing resp pkt %d len\n", (int)(p - response)); +#ifdef DEBUG + fwrite(response, 1, p - response, stderr); +#endif + n = libwebsocket_write(wsi, (unsigned char *)response, + p - response, LWS_WRITE_HTTP_HEADERS); + if (n != (p - response)) { + lwsl_debug("handshake_0405: ERROR writing to socket\n"); + goto bail; + } + + } + + /* alright clean up and set ourselves into established state */ + + wsi->state = WSI_STATE_ESTABLISHED; + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + + /* notify user code that we're ready to roll */ + + if (wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, LWS_CALLBACK_ESTABLISHED, + wsi->user_space, NULL, 0); + + return 0; + + +bail: + /* free up his parsing allocations */ + lws_free_header_table(wsi); + return -1; +} + diff --git a/src/engine/external/libwebsockets/server.c b/src/engine/external/libwebsockets/server.c new file mode 100644 index 00000000..ed5c47b2 --- /dev/null +++ b/src/engine/external/libwebsockets/server.c @@ -0,0 +1,1162 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + + +#include "private-libwebsockets.h" + +int lws_context_init_server(struct lws_context_creation_info *info, + struct libwebsocket_context *context) +{ + int n; + int sockfd; + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + int opt = 1; + struct libwebsocket *wsi; +#ifdef LWS_USE_IPV6 + struct sockaddr_in6 serv_addr6; +#endif + struct sockaddr_in serv_addr4; + struct sockaddr *v; + + /* set up our external listening socket we serve on */ + + if (info->port == CONTEXT_PORT_NO_LISTEN) + return 0; + +#ifdef LWS_USE_IPV6 + if (LWS_IPV6_ENABLED(context)) + sockfd = socket(AF_INET6, SOCK_STREAM, 0); + else +#endif + sockfd = socket(AF_INET, SOCK_STREAM, 0); + + if (sockfd < 0) { + lwsl_err("ERROR opening socket\n"); + return 1; + } + + /* + * allow us to restart even if old sockets in TIME_WAIT + */ + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (const void *)&opt, sizeof(opt)) < 0) { + compatible_close(sockfd); + return 1; + } + + lws_plat_set_socket_options(context, sockfd); + +#ifdef LWS_USE_IPV6 + if (LWS_IPV6_ENABLED(context)) { + v = (struct sockaddr *)&serv_addr6; + n = sizeof(struct sockaddr_in6); + bzero((char *) &serv_addr6, sizeof(serv_addr6)); + serv_addr6.sin6_addr = in6addr_any; + serv_addr6.sin6_family = AF_INET6; + serv_addr6.sin6_port = htons(info->port); + } else +#endif + { + v = (struct sockaddr *)&serv_addr4; + n = sizeof(serv_addr4); + bzero((char *) &serv_addr4, sizeof(serv_addr4)); + serv_addr4.sin_addr.s_addr = INADDR_ANY; + serv_addr4.sin_family = AF_INET; + + if (info->iface) { + if (interface_to_sa(context, info->iface, + (struct sockaddr_in *)v, n) < 0) { + lwsl_err("Unable to find interface %s\n", + info->iface); + compatible_close(sockfd); + return 1; + } + } + + serv_addr4.sin_port = htons(info->port); + } /* ipv4 */ + + n = bind(sockfd, v, n); + if (n < 0) { + lwsl_err("ERROR on binding to port %d (%d %d)\n", + info->port, n, LWS_ERRNO); + compatible_close(sockfd); + return 1; + } + + if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1) + lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO)); + else + info->port = ntohs(sin.sin_port); + + context->listen_port = info->port; + + wsi = lws_zalloc(sizeof(struct libwebsocket)); + if (wsi == NULL) { + lwsl_err("Out of mem\n"); + compatible_close(sockfd); + return 1; + } + wsi->sock = sockfd; + wsi->mode = LWS_CONNMODE_SERVER_LISTENER; + + insert_wsi_socket_into_fds(context, wsi); + + context->listen_service_modulo = LWS_LISTEN_SERVICE_MODULO; + context->listen_service_count = 0; + context->listen_service_fd = sockfd; + + listen(sockfd, LWS_SOMAXCONN); + lwsl_notice(" Listening on port %d\n", info->port); + + return 0; +} + +int +_libwebsocket_rx_flow_control(struct libwebsocket *wsi) +{ + struct libwebsocket_context *context = wsi->protocol->owning_server; + + /* there is no pending change */ + if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)) + return 0; + + /* stuff is still buffered, not ready to really accept new input */ + if (wsi->rxflow_buffer) { + /* get ourselves called back to deal with stashed buffer */ + libwebsocket_callback_on_writable(context, wsi); + return 0; + } + + /* pending is cleared, we can change rxflow state */ + + wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE; + + lwsl_info("rxflow: wsi %p change_to %d\n", wsi, + wsi->rxflow_change_to & LWS_RXFLOW_ALLOW); + + /* adjust the pollfd for this wsi */ + + if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) { + if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { + lwsl_info("%s: fail\n", __func__); + return -1; + } + } else + if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) + return -1; + + return 0; +} + +int lws_http_action(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + char *uri_ptr = NULL; + int uri_len = 0; + enum http_version request_version; + enum http_connection_type connection_type; + int http_version_len; + char content_length_str[32]; + char http_version_str[10]; + char http_conn_str[20]; + int n; + + /* it's not websocket.... shall we accept it as http? */ + + if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) && + !lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) && +#ifdef LWS_USE_HTTP2 + !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH) && +#endif + !lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) { + lwsl_warn("Missing URI in HTTP request\n"); + goto bail_nuke_ah; + } + + if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) && + lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { + lwsl_warn("GET and POST methods?\n"); + goto bail_nuke_ah; + } + + if (libwebsocket_ensure_user_space(wsi)) + goto bail_nuke_ah; + +#ifdef LWS_USE_HTTP2 + if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)) { + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH); + lwsl_info("HTTP2 request for '%s'\n", uri_ptr); + goto got_uri; + } +#endif + if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) { + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI); + lwsl_info("HTTP OPTIONS request for '%s'\n", uri_ptr); + goto got_uri; + } + if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI); + lwsl_info("HTTP POST request for '%s'\n", uri_ptr); + goto got_uri; + } + if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) { + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI); + lwsl_info("HTTP GET request for '%s'\n", uri_ptr); + } + +got_uri: + /* HTTP header had a content length? */ + + wsi->u.http.content_length = 0; + if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) + wsi->u.http.content_length = 100 * 1024 * 1024; + + if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { + lws_hdr_copy(wsi, content_length_str, + sizeof(content_length_str) - 1, + WSI_TOKEN_HTTP_CONTENT_LENGTH); + wsi->u.http.content_length = atoi(content_length_str); + } + + /* http_version? Default to 1.0, override with token: */ + request_version = HTTP_VERSION_1_0; + + /* Works for single digit HTTP versions. : */ + http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP); + if (http_version_len > 7) { + lws_hdr_copy(wsi, http_version_str, + sizeof(http_version_str) - 1, WSI_TOKEN_HTTP); + if (http_version_str[5] == '1' && http_version_str[7] == '1') + request_version = HTTP_VERSION_1_1; + } + wsi->u.http.request_version = request_version; + + /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */ + if (request_version == HTTP_VERSION_1_1) + connection_type = HTTP_CONNECTION_KEEP_ALIVE; + else + connection_type = HTTP_CONNECTION_CLOSE; + + /* Override default if http "Connection:" header: */ + if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) { + lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1, + WSI_TOKEN_CONNECTION); + http_conn_str[sizeof(http_conn_str) - 1] = '\0'; + if (!strcasecmp(http_conn_str, "keep-alive")) + connection_type = HTTP_CONNECTION_KEEP_ALIVE; + else + if (strcasecmp(http_conn_str, "close")) + connection_type = HTTP_CONNECTION_CLOSE; + } + wsi->u.http.connection_type = connection_type; + + n = 0; + if (wsi->protocol->callback) + n = wsi->protocol->callback(context, wsi, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + wsi->user_space, uri_ptr, uri_len); + + if (!n) { + /* + * if there is content supposed to be coming, + * put a timeout on it having arrived + */ + libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, + AWAITING_TIMEOUT); + + if (wsi->protocol->callback) + n = wsi->protocol->callback(context, wsi, + LWS_CALLBACK_HTTP, + wsi->user_space, uri_ptr, uri_len); + } + + /* now drop the header info we kept a pointer to */ + lws_free2(wsi->u.http.ah); + + if (n) { + lwsl_info("LWS_CALLBACK_HTTP closing\n"); + return 1; /* struct ah ptr already nuked */ } + + /* + * If we're not issuing a file, check for content_length or + * HTTP keep-alive. No keep-alive header allocation for + * ISSUING_FILE, as this uses HTTP/1.0. + * + * In any case, return 0 and let libwebsocket_read decide how to + * proceed based on state + */ + if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) + /* Prepare to read body if we have a content length: */ + if (wsi->u.http.content_length > 0) + wsi->state = WSI_STATE_HTTP_BODY; + + return 0; + +bail_nuke_ah: + /* drop the header info */ + lws_free2(wsi->u.hdr.ah); + + return 1; +} + + +int lws_handshake_server(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char **buf, size_t len) +{ + struct allocated_headers *ah; + int protocol_len; + char protocol_list[128]; + char protocol_name[32]; + char *p; + int n, hit; + + /* LWS_CONNMODE_WS_SERVING */ + + while (len--) { + if (libwebsocket_parse(context, wsi, *(*buf)++)) { + lwsl_info("libwebsocket_parse failed\n"); + goto bail_nuke_ah; + } + + if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE) + continue; + + lwsl_parser("libwebsocket_parse sees parsing complete\n"); + + wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT; + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + + /* is this websocket protocol or normal http 1.0? */ + + if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) || + !lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) { + + ah = wsi->u.hdr.ah; + + lws_union_transition(wsi, LWS_CONNMODE_HTTP_SERVING_ACCEPTED); + wsi->state = WSI_STATE_HTTP; + wsi->u.http.fd = LWS_INVALID_FILE; + + /* expose it at the same offset as u.hdr */ + wsi->u.http.ah = ah; + + n = lws_http_action(context, wsi); + + return n; + } + + if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), + "websocket")) + goto upgrade_ws; +#ifdef LWS_USE_HTTP2 + if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), + "h2c-14")) + goto upgrade_h2c; +#endif + /* dunno what he wanted to upgrade to */ + goto bail_nuke_ah; + +#ifdef LWS_USE_HTTP2 +upgrade_h2c: + if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) { + lwsl_err("missing http2_settings\n"); + goto bail_nuke_ah; + } + + lwsl_err("h2c upgrade...\n"); + + p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS); + /* convert the peer's HTTP-Settings */ + n = lws_b64_decode_string(p, protocol_list, sizeof(protocol_list)); + if (n < 0) { + lwsl_parser("HTTP2_SETTINGS too long\n"); + return 1; + } + + /* adopt the header info */ + + ah = wsi->u.hdr.ah; + + lws_union_transition(wsi, LWS_CONNMODE_HTTP2_SERVING); + + /* http2 union member has http union struct at start */ + wsi->u.http.ah = ah; + + lws_http2_init(&wsi->u.http2.peer_settings); + lws_http2_init(&wsi->u.http2.my_settings); + + /* HTTP2 union */ + + lws_http2_interpret_settings_payload(&wsi->u.http2.peer_settings, (unsigned char *)protocol_list, n); + + strcpy(protocol_list, + "HTTP/1.1 101 Switching Protocols\x0d\x0a" + "Connection: Upgrade\x0d\x0a" + "Upgrade: h2c\x0d\x0a\x0d\x0a"); + n = lws_issue_raw(wsi, (unsigned char *)protocol_list, + strlen(protocol_list)); + if (n != strlen(protocol_list)) { + lwsl_debug("http2 switch: ERROR writing to socket\n"); + return 1; + } + + wsi->state = WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE; + + return 0; +#endif + +upgrade_ws: + if (!wsi->protocol) + lwsl_err("NULL protocol at libwebsocket_read\n"); + + /* + * It's websocket + * + * Select the first protocol we support from the list + * the client sent us. + * + * Copy it to remove header fragmentation + */ + + if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1, + WSI_TOKEN_PROTOCOL) < 0) { + lwsl_err("protocol list too long"); + goto bail_nuke_ah; + } + + protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL); + protocol_list[protocol_len] = '\0'; + p = protocol_list; + hit = 0; + + while (*p && !hit) { + n = 0; + while (n < sizeof(protocol_name) - 1 && *p && *p !=',') + protocol_name[n++] = *p++; + protocol_name[n] = '\0'; + if (*p) + p++; + + lwsl_info("checking %s\n", protocol_name); + + n = 0; + while (wsi->protocol && context->protocols[n].callback) { + if (!wsi->protocol->name) { + n++; + continue; + } + if (!strcmp(context->protocols[n].name, + protocol_name)) { + lwsl_info("prot match %d\n", n); + wsi->protocol = &context->protocols[n]; + hit = 1; + break; + } + + n++; + } + } + + /* we didn't find a protocol he wanted? */ + + if (!hit) { + if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) == + NULL) { + /* + * some clients only have one protocol and + * do not sent the protocol list header... + * allow it and match to protocol 0 + */ + lwsl_info("defaulting to prot 0 handler\n"); + wsi->protocol = &context->protocols[0]; + } else { + lwsl_err("No protocol from list \"%s\" supported\n", + protocol_list); + goto bail_nuke_ah; + } + } + + /* allocate wsi->user storage */ + if (libwebsocket_ensure_user_space(wsi)) + goto bail_nuke_ah; + + /* + * Give the user code a chance to study the request and + * have the opportunity to deny it + */ + + if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + wsi->user_space, + lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) { + lwsl_warn("User code denied connection\n"); + goto bail_nuke_ah; + } + + + /* + * Perform the handshake according to the protocol version the + * client announced + */ + + switch (wsi->ietf_spec_revision) { + case 13: + lwsl_parser("lws_parse calling handshake_04\n"); + if (handshake_0405(context, wsi)) { + lwsl_info("hs0405 has failed the connection\n"); + goto bail_nuke_ah; + } + break; + + default: + lwsl_warn("Unknown client spec version %d\n", + wsi->ietf_spec_revision); + goto bail_nuke_ah; + } + + /* drop the header info -- no bail_nuke_ah after this */ + lws_free_header_table(wsi); + + lws_union_transition(wsi, LWS_CONNMODE_WS_SERVING); + + /* + * create the frame buffer for this connection according to the + * size mentioned in the protocol definition. If 0 there, use + * a big default for compatibility + */ + + n = wsi->protocol->rx_buffer_size; + if (!n) + n = LWS_MAX_SOCKET_IO_BUF; + n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING; + wsi->u.ws.rx_user_buffer = lws_malloc(n); + if (!wsi->u.ws.rx_user_buffer) { + lwsl_err("Out of Mem allocating rx buffer %d\n", n); + return 1; + } + lwsl_info("Allocating RX buffer %d\n", n); + + if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) { + lwsl_warn("Failed to set SNDBUF to %d", n); + return 1; + } + + lwsl_parser("accepted v%02d connection\n", + wsi->ietf_spec_revision); + } /* while all chars are handled */ + + return 0; + +bail_nuke_ah: + /* drop the header info */ + lws_free_header_table(wsi); + return 1; +} + +struct libwebsocket * +libwebsocket_create_new_server_wsi(struct libwebsocket_context *context) +{ + struct libwebsocket *new_wsi; + + new_wsi = lws_zalloc(sizeof(struct libwebsocket)); + if (new_wsi == NULL) { + lwsl_err("Out of memory for new connection\n"); + return NULL; + } + + new_wsi->pending_timeout = NO_PENDING_TIMEOUT; + new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; + + /* intialize the instance struct */ + + new_wsi->state = WSI_STATE_HTTP; + new_wsi->mode = LWS_CONNMODE_HTTP_SERVING; + new_wsi->hdr_parsing_completed = 0; + + if (lws_allocate_header_table(new_wsi)) { + lws_free(new_wsi); + return NULL; + } + + /* + * 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 + */ + new_wsi->protocol = context->protocols; + new_wsi->user_space = NULL; + new_wsi->ietf_spec_revision = 0; + + /* + * outermost create notification for wsi + * no user_space because no protocol selection + */ + context->protocols[0].callback(context, new_wsi, + LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0); + + return new_wsi; +} + +/** + * lws_http_transaction_completed() - wait for new http transaction or close + * @wsi: websocket connection + * + * Returns 1 if the HTTP connection must close now + * Returns 0 and resets connection to wait for new HTTP header / + * transaction if possible + */ + +LWS_VISIBLE +int lws_http_transaction_completed(struct libwebsocket *wsi) +{ + /* if we can't go back to accept new headers, drop the connection */ + if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) { + lwsl_info("%s: close connection\n", __func__); + return 1; + } + + /* otherwise set ourselves up ready to go again */ + wsi->state = WSI_STATE_HTTP; + + lwsl_info("%s: await new transaction\n", __func__); + + return 0; +} + +int lws_server_socket_service(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd) +{ + struct libwebsocket *new_wsi = NULL; + int accept_fd = 0; + socklen_t clilen; + struct sockaddr_in cli_addr; + int n; + int len; + + switch (wsi->mode) { + + case LWS_CONNMODE_HTTP_SERVING: + case LWS_CONNMODE_HTTP_SERVING_ACCEPTED: + case LWS_CONNMODE_HTTP2_SERVING: + + /* handle http headers coming in */ + + /* pending truncated sends have uber priority */ + + if (wsi->truncated_send_len) { + if (pollfd->revents & LWS_POLLOUT) + if (lws_issue_raw(wsi, wsi->truncated_send_malloc + + wsi->truncated_send_offset, + wsi->truncated_send_len) < 0) { + lwsl_info("closing from socket service\n"); + return -1; + } + /* + * we can't afford to allow input processing send + * something new, so spin around he event loop until + * he doesn't have any partials + */ + break; + } + + /* any incoming data ready? */ + + if (pollfd->revents & LWS_POLLIN) { + len = lws_ssl_capable_read(context, wsi, + context->service_buffer, + sizeof(context->service_buffer)); + switch (len) { + case 0: + lwsl_info("lws_server_skt_srv: read 0 len\n"); + /* lwsl_info(" state=%d\n", wsi->state); */ + if (!wsi->hdr_parsing_completed) + lws_free_header_table(wsi); + /* fallthru */ + case LWS_SSL_CAPABLE_ERROR: + libwebsocket_close_and_free_session( + context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 0; + case LWS_SSL_CAPABLE_MORE_SERVICE: + goto try_pollout; + } + + /* just ignore incoming if waiting for close */ + if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) { + + /* hm this may want to send (via HTTP callback for example) */ + n = libwebsocket_read(context, wsi, + context->service_buffer, len); + if (n < 0) + /* we closed wsi */ + return 0; + + /* hum he may have used up the writability above */ + break; + } + } + +try_pollout: + /* this handles POLLOUT for http serving fragments */ + + if (!(pollfd->revents & LWS_POLLOUT)) + break; + + /* one shot */ + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) + goto fail; + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); + + if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) { + n = user_callback_handle_rxflow( + wsi->protocol->callback, + wsi->protocol->owning_server, + wsi, LWS_CALLBACK_HTTP_WRITEABLE, + wsi->user_space, + NULL, + 0); + if (n < 0) + goto fail; + break; + } + + /* >0 == completion, <0 == error */ + n = libwebsockets_serve_http_file_fragment(context, wsi); + if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) + goto fail; + break; + + case LWS_CONNMODE_SERVER_LISTENER: + + /* pollin means a client has connected to us then */ + + if (!(pollfd->revents & LWS_POLLIN)) + break; + + /* listen socket got an unencrypted connection... */ + + clilen = sizeof(cli_addr); + lws_latency_pre(context, wsi); + accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr, + &clilen); + lws_latency(context, wsi, + "unencrypted accept LWS_CONNMODE_SERVER_LISTENER", + accept_fd, accept_fd >= 0); + if (accept_fd < 0) { + if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) { + lwsl_debug("accept asks to try again\n"); + break; + } + lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO)); + break; + } + + lws_plat_set_socket_options(context, accept_fd); + + /* + * look at who we connected to and give user code a chance + * to reject based on client IP. There's no protocol selected + * yet so we issue this to protocols[0] + */ + + if ((context->protocols[0].callback)(context, wsi, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + NULL, (void *)(long)accept_fd, 0)) { + lwsl_debug("Callback denied network connection\n"); + compatible_close(accept_fd); + break; + } + + new_wsi = libwebsocket_create_new_server_wsi(context); + if (new_wsi == NULL) { + compatible_close(accept_fd); + break; + } + + new_wsi->sock = accept_fd; + + /* the transport is accepted... give him time to negotiate */ + libwebsocket_set_timeout(new_wsi, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + AWAITING_TIMEOUT); + + /* + * A new connection was accepted. Give the user a chance to + * set properties of the newly created wsi. There's no protocol + * selected yet so we issue this to protocols[0] + */ + + (context->protocols[0].callback)(context, new_wsi, + LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0); + + lws_libev_accept(context, new_wsi, accept_fd); + + if (!LWS_SSL_ENABLED(context)) { + lwsl_debug("accepted new conn port %u on fd=%d\n", + ntohs(cli_addr.sin_port), accept_fd); + + insert_wsi_socket_into_fds(context, new_wsi); + } + break; + + default: + break; + } + + if (lws_server_socket_service_ssl(context, &wsi, new_wsi, + accept_fd, pollfd)) + goto fail; + + return 0; + +fail: + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; +} + +#include "lextable-strings.h" + +const unsigned char *lws_token_to_string(enum lws_token_indexes token) +{ + if ((unsigned int)token >= ARRAY_SIZE(set)) + return NULL; + + return (unsigned char *)set[token]; +} + +int lws_add_http_header_by_name(struct libwebsocket_context *context, + struct libwebsocket *wsi, + const unsigned char *name, + const unsigned char *value, + int length, + unsigned char **p, + unsigned char *end) +{ +#ifdef LWS_USE_HTTP2 + if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) + return lws_add_http2_header_by_name(context, wsi, name, value, length, p, end); +#endif + if (name) { + while (*p < end && *name) + *((*p)++) = *name++; + + if (*p == end) + return 1; + + *((*p)++) = ' '; + } + if (*p + length + 3 >= end) + return 1; + + memcpy(*p, value, length); + *p += length; + + *((*p)++) = '\x0d'; + *((*p)++) = '\x0a'; + + return 0; +} + +int lws_finalize_http_header(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char **p, + unsigned char *end) +{ +#ifdef LWS_USE_HTTP2 + if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) + return 0; +#endif + + if ((long)(end - *p) < 3) + return 1; + + *((*p)++) = '\x0d'; + *((*p)++) = '\x0a'; + + return 0; +} + +int lws_add_http_header_by_token(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum lws_token_indexes token, + const unsigned char *value, + int length, + unsigned char **p, + unsigned char *end) +{ + const unsigned char *name; +#ifdef LWS_USE_HTTP2 + if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) + return lws_add_http2_header_by_token(context, wsi, token, value, length, p, end); +#endif + name = lws_token_to_string(token); + if (!name) + return 1; + + return lws_add_http_header_by_name(context, wsi, name, value, length, p, end); +} + +int lws_add_http_header_content_length(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned long content_length, + unsigned char **p, + unsigned char *end) +{ + char b[24]; + int n; + + n = sprintf(b, "%lu", content_length); + if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)b, n, p, end)) + return 1; + wsi->u.http.content_length = content_length; + wsi->u.http.content_remain = content_length; + + return 0; +} + +static const char *err400[] = { + "Bad Request", + "Unauthorized", + "Payment Required", + "Forbidden", + "Not Found", + "Method Not Allowed", + "Not Acceptable", + "Proxy Auth Required", + "Request Timeout", + "Conflict", + "Gone", + "Length Required", + "Precondition Failed", + "Request Entity Too Large", + "Request URI too Long", + "Unsupported Media Type", + "Requested Range Not Satisfiable", + "Expectation Failed" +}; + +static const char *err500[] = { + "Internal Server Error", + "Not Implemented", + "Bad Gateway", + "Service Unavailable", + "Gateway Timeout", + "HTTP Version Not Supported" +}; + +int lws_add_http_header_status(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned int code, + unsigned char **p, + unsigned char *end) +{ + unsigned char code_and_desc[60]; + const char *description = ""; + int n; + +#ifdef LWS_USE_HTTP2 + if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) + return lws_add_http2_header_status(context, wsi, code, p, end); +#endif + if (code >= 400 && code < (400 + ARRAY_SIZE(err400))) + description = err400[code - 400]; + if (code >= 500 && code < (500 + ARRAY_SIZE(err500))) + description = err500[code - 500]; + + n = sprintf((char *)code_and_desc, "HTTP/1.0 %u %s", code, description); + + return lws_add_http_header_by_name(context, wsi, NULL, code_and_desc, n, p, end); +} + +/** + * libwebsockets_return_http_status() - Return simple http status + * @context: libwebsockets context + * @wsi: Websocket instance (available from user callback) + * @code: Status index, eg, 404 + * @html_body: User-readable HTML description < 1KB, or NULL + * + * Helper to report HTTP errors back to the client cleanly and + * consistently + */ +LWS_VISIBLE int libwebsockets_return_http_status( + struct libwebsocket_context *context, struct libwebsocket *wsi, + unsigned int code, const char *html_body) +{ + int n, m; + + unsigned char *p = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING; + unsigned char *start = p; + unsigned char *end = p + sizeof(context->service_buffer) - + LWS_SEND_BUFFER_PRE_PADDING; + + if (!html_body) + html_body = ""; + + if (lws_add_http_header_status(context, wsi, code, &p, end)) + return 1; + if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) + return 1; + if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) + return 1; + if (lws_finalize_http_header(context, wsi, &p, end)) + return 1; + + m = libwebsocket_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); + if (m != (int)(p - start)) + return 1; + + n = sprintf((char *)start, "<html><body><h1>%u</h1>%s</body></html>", code, html_body); + m = libwebsocket_write(wsi, start, n, LWS_WRITE_HTTP); + + return m != n; +} + +/** + * libwebsockets_serve_http_file() - Send a file back to the client using http + * @context: libwebsockets context + * @wsi: Websocket instance (available from user callback) + * @file: The file to issue over http + * @content_type: The http content type, eg, text/html + * @other_headers: NULL or pointer to \0-terminated other header string + * + * 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. + * + * Returning <0 indicates error and the wsi should be closed. Returning + * >0 indicates the file was completely sent and + * lws_http_transaction_completed() called on the wsi (and close if != 0) + * ==0 indicates the file transfer is started and needs more service later, + * the wsi should be left alone. + */ + +LWS_VISIBLE int libwebsockets_serve_http_file( + struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type, const char *other_headers, + int other_headers_len) +{ + unsigned char *response = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING; + unsigned char *p = response; + unsigned char *end = p + sizeof(context->service_buffer) - + LWS_SEND_BUFFER_PRE_PADDING; + int ret = 0; + + wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen); + + if (wsi->u.http.fd == LWS_INVALID_FILE) { + lwsl_err("Unable to open '%s'\n", file); + libwebsockets_return_http_status(context, wsi, + HTTP_STATUS_NOT_FOUND, NULL); + return -1; + } + + if (lws_add_http_header_status(context, wsi, 200, &p, end)) + return -1; + if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) + return -1; + if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)content_type, strlen(content_type), &p, end)) + return -1; + if (lws_add_http_header_content_length(context, wsi, wsi->u.http.filelen, &p, end)) + return -1; + + if (other_headers) { + if ((end - p) < other_headers_len) + return -1; + memcpy(p, other_headers, other_headers_len); + p += other_headers_len; + } + + if (lws_finalize_http_header(context, wsi, &p, end)) + return -1; + + ret = libwebsocket_write(wsi, response, + p - response, LWS_WRITE_HTTP_HEADERS); + if (ret != (p - response)) { + lwsl_err("_write returned %d from %d\n", ret, (p - response)); + return -1; + } + + wsi->u.http.filepos = 0; + wsi->state = WSI_STATE_HTTP_ISSUING_FILE; + + return libwebsockets_serve_http_file_fragment(context, wsi); +} + + +int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, + unsigned char *buf, size_t len) +{ + size_t n = 0; + int m; + +#if 0 + lwsl_parser("received %d byte packet\n", (int)len); + lwsl_hexdump(buf, len); +#endif + + /* let the rx protocol state machine have as much as it needs */ + + while (n < len) { + /* + * we were accepting input but now we stopped doing so + */ + if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { + lws_rxflow_cache(wsi, buf, n, len); + + return 1; + } + + /* account for what we're using in rxflow buffer */ + if (wsi->rxflow_buffer) + wsi->rxflow_pos++; + + /* process the byte */ + m = libwebsocket_rx_sm(wsi, buf[n++]); + if (m < 0) + return -1; + } + + return 0; +} + +LWS_VISIBLE void +lws_server_get_canonical_hostname(struct libwebsocket_context *context, + struct lws_context_creation_info *info) +{ + if (info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME) + return; + + /* find canonical hostname */ + gethostname((char *)context->canonical_hostname, + sizeof(context->canonical_hostname) - 1); + + lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname); +} diff --git a/src/engine/external/libwebsockets/service.c b/src/engine/external/libwebsockets/service.c new file mode 100644 index 00000000..f905a605 --- /dev/null +++ b/src/engine/external/libwebsockets/service.c @@ -0,0 +1,636 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +static int +lws_calllback_as_writeable(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + int n; + + switch (wsi->mode) { + case LWS_CONNMODE_WS_CLIENT: + n = LWS_CALLBACK_CLIENT_WRITEABLE; + break; + case LWS_CONNMODE_WS_SERVING: + n = LWS_CALLBACK_SERVER_WRITEABLE; + break; + default: + n = LWS_CALLBACK_HTTP_WRITEABLE; + break; + } + lwsl_info("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space); + return user_callback_handle_rxflow(wsi->protocol->callback, context, + wsi, (enum libwebsocket_callback_reasons) n, + wsi->user_space, NULL, 0); +} + +int +lws_handle_POLLOUT_event(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd) +{ + int n; + struct lws_tokens eff_buf; +#ifdef LWS_USE_HTTP2 + struct libwebsocket *wsi2; +#endif + int ret; + int m; + + /* pending truncated sends have uber priority */ + + if (wsi->truncated_send_len) { + if (lws_issue_raw(wsi, wsi->truncated_send_malloc + + wsi->truncated_send_offset, + wsi->truncated_send_len) < 0) { + lwsl_info("lws_handle_POLLOUT_event signalling to close\n"); + return -1; + } + /* leave POLLOUT active either way */ + return 0; + } else + if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) { + lwsl_info("***** %x signalling to close in POLLOUT handler\n", wsi); + return -1; /* retry closing now */ + } +#ifdef LWS_USE_HTTP2 + /* protocol packets are next */ + if (wsi->pps) { + lwsl_info("servicing pps %d\n", wsi->pps); + switch (wsi->pps) { + case LWS_PPS_HTTP2_MY_SETTINGS: + case LWS_PPS_HTTP2_ACK_SETTINGS: + lws_http2_do_pps_send(context, wsi); + break; + default: + break; + } + wsi->pps = LWS_PPS_NONE; + libwebsocket_rx_flow_control(wsi, 1); + + return 0; /* leave POLLOUT active */ + } +#endif + /* pending control packets have next priority */ + + if (wsi->state == WSI_STATE_ESTABLISHED && wsi->u.ws.ping_payload_len) { + n = libwebsocket_write(wsi, + &wsi->u.ws.ping_payload_buf[ + LWS_SEND_BUFFER_PRE_PADDING], + wsi->u.ws.ping_payload_len, + LWS_WRITE_PONG); + if (n < 0) + return -1; + /* well he is sent, mark him done */ + wsi->u.ws.ping_payload_len = 0; + /* leave POLLOUT active either way */ + return 0; + } + + /* if nothing critical, user can get the callback */ + + m = lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_IS_WRITEABLE, + NULL, 0); +#ifndef LWS_NO_EXTENSIONS + if (!wsi->extension_data_pending) + goto user_service; +#endif + /* + * check in on the active extensions, see if they + * had pending stuff to spill... they need to get the + * first look-in otherwise sequence will be disordered + * + * NULL, zero-length eff_buf means just spill pending + */ + + ret = 1; + while (ret == 1) { + + /* default to nobody has more to spill */ + + ret = 0; + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* give every extension a chance to spill */ + + m = lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + &eff_buf, 0); + if (m < 0) { + lwsl_err("ext reports fatal error\n"); + return -1; + } + if (m) + /* + * at least one extension told us he has more + * to spill, so we will go around again after + */ + ret = 1; + + /* assuming they gave us something to send, send it */ + + if (eff_buf.token_len) { + n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len); + if (n < 0) { + lwsl_info("closing from POLLOUT spill\n"); + return -1; + } + /* + * Keep amount spilled small to minimize chance of this + */ + if (n != eff_buf.token_len) { + lwsl_err("Unable to spill ext %d vs %s\n", + eff_buf.token_len, n); + return -1; + } + } else + continue; + + /* no extension has more to spill */ + + if (!ret) + continue; + + /* + * There's more to spill from an extension, but we just sent + * something... did that leave the pipe choked? + */ + + if (!lws_send_pipe_choked(wsi)) + /* no we could add more */ + continue; + + lwsl_info("choked in POLLOUT service\n"); + + /* + * Yes, he's choked. Leave the POLLOUT masked on so we will + * come back here when he is unchoked. Don't call the user + * callback to enforce ordering of spilling, he'll get called + * when we come back here and there's nothing more to spill. + */ + + return 0; + } +#ifndef LWS_NO_EXTENSIONS + wsi->extension_data_pending = 0; + +user_service: +#endif + /* one shot */ + + if (pollfd) { + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { + lwsl_info("failled at set pollfd\n"); + return 1; + } + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); + } + +#ifdef LWS_USE_HTTP2 + /* + * we are the 'network wsi' for potentially many muxed child wsi with + * no network connection of their own, who have to use us for all their + * network actions. So we use a round-robin scheme to share out the + * POLLOUT notifications to our children. + * + * But because any child could exhaust the socket's ability to take + * writes, we can only let one child get notified each time. + * + * In addition children may be closed / deleted / added between POLLOUT + * notifications, so we can't hold pointers + */ + + if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) { + lwsl_info("%s: non http2\n", __func__); + goto notify; + } + + wsi->u.http2.requested_POLLOUT = 0; + if (!wsi->u.http2.initialized) { + lwsl_info("pollout on uninitialized http2 conn\n"); + return 0; + } + + lwsl_info("%s: doing children\n", __func__); + + wsi2 = wsi; + do { + wsi2 = wsi2->u.http2.next_child_wsi; + lwsl_info("%s: child %p\n", __func__, wsi2); + if (!wsi2) + continue; + if (!wsi2->u.http2.requested_POLLOUT) + continue; + wsi2->u.http2.requested_POLLOUT = 0; + if (lws_calllback_as_writeable(context, wsi2)) { + lwsl_debug("Closing POLLOUT child\n"); + libwebsocket_close_and_free_session(context, wsi2, + LWS_CLOSE_STATUS_NOSTATUS); + } + wsi2 = wsi; + } while (wsi2 != NULL && !lws_send_pipe_choked(wsi)); + + lwsl_info("%s: completed\n", __func__); + + return 0; +notify: +#endif + return lws_calllback_as_writeable(context, wsi); +} + + + +int +libwebsocket_service_timeout_check(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int sec) +{ + /* + * if extensions want in on it (eg, we are a mux parent) + * give them a chance to service child timeouts + */ + if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_1HZ, NULL, sec) < 0) + return 0; + + if (!wsi->pending_timeout) + return 0; + + /* + * if we went beyond the allowed time, kill the + * connection + */ + if (sec > wsi->pending_timeout_limit) { + lwsl_info("TIMEDOUT WAITING on %d\n", wsi->pending_timeout); + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + + return 0; +} + +int lws_rxflow_cache(struct libwebsocket *wsi, unsigned char *buf, int n, int len) +{ + /* his RX is flowcontrolled, don't send remaining now */ + if (wsi->rxflow_buffer) { + /* rxflow while we were spilling prev rxflow */ + lwsl_info("stalling in existing rxflow buf\n"); + return 1; + } + + /* a new rxflow, buffer it and warn caller */ + lwsl_info("new rxflow input buffer len %d\n", len - n); + wsi->rxflow_buffer = lws_malloc(len - n); + wsi->rxflow_len = len - n; + wsi->rxflow_pos = 0; + memcpy(wsi->rxflow_buffer, buf + n, len - n); + + return 0; +} + +/** + * libwebsocket_service_fd() - Service polled socket with something waiting + * @context: Websocket context + * @pollfd: The pollfd entry describing the socket fd and which events + * happened. + * + * This function takes a pollfd that has POLLIN or POLLOUT activity and + * services it according to the state of the associated + * struct libwebsocket. + * + * The one call deals with all "service" that might happen on a socket + * including listen accepts, http files as well as websocket protocol. + * + * If a pollfd says it has something, you can just pass it to + * libwebsocket_serice_fd() whether it is a socket handled by lws or not. + * If it sees it is a lws socket, the traffic will be handled and + * pollfd->revents will be zeroed now. + * + * If the socket is foreign to lws, it leaves revents alone. So you can + * see if you should service yourself by checking the pollfd revents + * after letting lws try to service it. + */ + +LWS_VISIBLE int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct libwebsocket_pollfd *pollfd) +{ + struct libwebsocket *wsi; + int n; + int m; + int listen_socket_fds_index = 0; + time_t now; + int timed_out = 0; + int our_fd = 0; + char draining_flow = 0; + int more; + struct lws_tokens eff_buf; + + if (context->listen_service_fd) + listen_socket_fds_index = context->lws_lookup[ + context->listen_service_fd]->position_in_fds_table; + + /* + * you can call us with pollfd = NULL to just allow the once-per-second + * global timeout checks; if less than a second since the last check + * it returns immediately then. + */ + + time(&now); + + /* TODO: if using libev, we should probably use timeout watchers... */ + if (context->last_timeout_check_s != now) { + context->last_timeout_check_s = now; + + lws_plat_service_periodic(context); + + /* global timeout check once per second */ + + if (pollfd) + our_fd = pollfd->fd; + + for (n = 0; n < context->fds_count; n++) { + m = context->fds[n].fd; + wsi = context->lws_lookup[m]; + if (!wsi) + continue; + + if (libwebsocket_service_timeout_check(context, wsi, now)) + /* he did time out... */ + if (m == our_fd) { + /* it was the guy we came to service! */ + timed_out = 1; + /* mark as handled */ + if (pollfd) + pollfd->revents = 0; + } + } + } + + /* the socket we came to service timed out, nothing to do */ + if (timed_out) + return 0; + + /* just here for timeout management? */ + if (pollfd == NULL) + return 0; + + /* no, here to service a socket descriptor */ + wsi = context->lws_lookup[pollfd->fd]; + if (wsi == NULL) + /* not lws connection ... leave revents alone and return */ + return 0; + + /* + * so that caller can tell we handled, past here we need to + * zero down pollfd->revents after handling + */ + + /* + * deal with listen service piggybacking + * every listen_service_modulo services of other fds, we + * sneak one in to service the listen socket if there's anything waiting + * + * To handle connection storms, as found in ab, if we previously saw a + * pending connection here, it causes us to check again next time. + */ + + if (context->listen_service_fd && pollfd != + &context->fds[listen_socket_fds_index]) { + context->listen_service_count++; + if (context->listen_service_extraseen || + context->listen_service_count == + context->listen_service_modulo) { + context->listen_service_count = 0; + m = 1; + if (context->listen_service_extraseen > 5) + m = 2; + while (m--) { + /* + * even with extpoll, we prepared this + * internal fds for listen + */ + n = lws_poll_listen_fd(&context->fds[listen_socket_fds_index]); + if (n > 0) { /* there's a conn waiting for us */ + libwebsocket_service_fd(context, + &context-> + fds[listen_socket_fds_index]); + context->listen_service_extraseen++; + } else { + if (context->listen_service_extraseen) + context-> + listen_service_extraseen--; + break; + } + } + } + + } + + /* handle session socket closed */ + + if ((!(pollfd->revents & LWS_POLLIN)) && + (pollfd->revents & LWS_POLLHUP)) { + + lwsl_debug("Session Socket %p (fd=%d) dead\n", + (void *)wsi, pollfd->fd); + + goto close_and_handled; + } + + /* okay, what we came here to do... */ + + switch (wsi->mode) { + case LWS_CONNMODE_HTTP_SERVING: + case LWS_CONNMODE_HTTP_SERVING_ACCEPTED: + case LWS_CONNMODE_SERVER_LISTENER: + case LWS_CONNMODE_SSL_ACK_PENDING: + n = lws_server_socket_service(context, wsi, pollfd); + if (n < 0) + goto close_and_handled; + goto handled; + + case LWS_CONNMODE_WS_SERVING: + case LWS_CONNMODE_WS_CLIENT: + case LWS_CONNMODE_HTTP2_SERVING: + + /* the guy requested a callback when it was OK to write */ + + if ((pollfd->revents & LWS_POLLOUT) && + (wsi->state == WSI_STATE_ESTABLISHED || wsi->state == WSI_STATE_HTTP2_ESTABLISHED || wsi->state == WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS || + wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) && + lws_handle_POLLOUT_event(context, wsi, pollfd)) { + lwsl_info("libwebsocket_service_fd: closing\n"); + goto close_and_handled; + } + + if (wsi->rxflow_buffer && + (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { + lwsl_info("draining rxflow\n"); + /* well, drain it */ + eff_buf.token = (char *)wsi->rxflow_buffer + + wsi->rxflow_pos; + eff_buf.token_len = wsi->rxflow_len - wsi->rxflow_pos; + draining_flow = 1; + goto drain; + } + + /* any incoming data ready? */ + + if (!(pollfd->revents & LWS_POLLIN)) + break; + + eff_buf.token_len = lws_ssl_capable_read(context, wsi, + context->service_buffer, + sizeof(context->service_buffer)); + switch (eff_buf.token_len) { + case 0: + lwsl_info("service_fd: closing due to 0 length read\n"); + goto close_and_handled; + case LWS_SSL_CAPABLE_MORE_SERVICE: + lwsl_info("SSL Capable more service\n"); + n = 0; + goto handled; + case LWS_SSL_CAPABLE_ERROR: + lwsl_info("Closing when error\n"); + goto close_and_handled; + } + + /* + * give any active extensions a chance to munge the buffer + * before parse. We pass in a pointer to an lws_tokens struct + * prepared with the default buffer and content length that's in + * there. Rather than rewrite the default buffer, extensions + * that expect to grow the buffer can adapt .token to + * point to their own per-connection buffer in the extension + * user allocation. By default with no extensions or no + * extension callback handling, just the normal input buffer is + * used then so it is efficient. + */ + + eff_buf.token = (char *)context->service_buffer; +drain: + + do { + + more = 0; + + m = lws_ext_callback_for_each_active(wsi, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, &eff_buf, 0); + if (m < 0) + goto close_and_handled; + if (m) + more = 1; + + /* service incoming data */ + + if (eff_buf.token_len) { + n = libwebsocket_read(context, wsi, + (unsigned char *)eff_buf.token, + eff_buf.token_len); + if (n < 0) { + /* we closed wsi */ + n = 0; + goto handled; + } + } + + eff_buf.token = NULL; + eff_buf.token_len = 0; + } while (more); + + if (draining_flow && wsi->rxflow_buffer && + wsi->rxflow_pos == wsi->rxflow_len) { + lwsl_info("flow buffer: drained\n"); + lws_free2(wsi->rxflow_buffer); + /* having drained the rxflow buffer, can rearm POLLIN */ +#ifdef LWS_NO_SERVER + n = +#endif + _libwebsocket_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */ + } + + break; + + default: +#ifdef LWS_NO_CLIENT + break; +#else + n = lws_client_socket_service(context, wsi, pollfd); + goto handled; +#endif + } + + n = 0; + goto handled; + +close_and_handled: + lwsl_debug("Close and handled\n"); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + n = 1; + +handled: + pollfd->revents = 0; + return n; +} + +/** + * libwebsocket_service() - Service any pending websocket activity + * @context: Websocket context + * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed + * service otherwise block and service immediately, returning + * after the timeout if nothing needed service. + * + * This function deals with any pending websocket traffic, for three + * kinds of event. It handles these events on both server and client + * types of connection the same. + * + * 1) Accept new connections to our context's server + * + * 2) Call the receive callback for incoming frame data received by + * server or client connections. + * + * You need to call this service function periodically to all the above + * functions to happen; if your application is single-threaded you can + * just call it in your main event loop. + * + * Alternatively you can fork a new process that asynchronously handles + * calling this service in a loop. In that case you are happy if this + * call blocks your thread until it needs to take care of something and + * would call it with a large nonzero timeout. Your loop then takes no + * CPU while there is nothing happening. + * + * If you are calling it in a single-threaded app, you don't want it to + * wait around blocking other things in your loop from happening, so you + * would call it with a timeout_ms of 0, so it returns immediately if + * nothing is pending, or as soon as it services whatever was pending. + */ + +LWS_VISIBLE int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms) +{ + return lws_plat_service(context, timeout_ms); +} + diff --git a/src/engine/external/libwebsockets/sha-1.c b/src/engine/external/libwebsockets/sha-1.c new file mode 100644 index 00000000..e68ee38d --- /dev/null +++ b/src/engine/external/libwebsockets/sha-1.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org> + */ + +#include "private-libwebsockets.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +struct sha1_ctxt { + union { + unsigned char b8[20]; + unsigned int b32[5]; + } h; + union { + unsigned char b8[8]; + u_int64_t b64[1]; + } c; + union { + unsigned char b8[64]; + unsigned int b32[16]; + } m; + unsigned char count; +}; + +/* sanity check */ +#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) +# define unsupported 1 +#elif BYTE_ORDER != BIG_ENDIAN +# if BYTE_ORDER != LITTLE_ENDIAN +# define unsupported 1 +# endif +#endif + +#ifndef unsupported + +/* constant table */ +static const unsigned int _K[] = + { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; +#define K(t) _K[(t) / 20] + +#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F1(b, c, d) (((b) ^ (c)) ^ (d)) +#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F3(b, c, d) (((b) ^ (c)) ^ (d)) + +#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) + +#define H(n) (ctxt->h.b32[(n)]) +#define COUNT (ctxt->count) +#define BCOUNT (ctxt->c.b64[0] / 8) +#define W(n) (ctxt->m.b32[(n)]) + +#define PUTBYTE(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + ctxt->c.b64[0] += 8; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +#define PUTPAD(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +static void sha1_step __P((struct sha1_ctxt *)); + +static void +sha1_step(struct sha1_ctxt *ctxt) +{ + unsigned int a, b, c, d, e, tmp; + size_t t, s; + +#if BYTE_ORDER == LITTLE_ENDIAN + struct sha1_ctxt tctxt; + + memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64); + ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; + ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; + ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; + ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; + ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; + ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; + ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; + ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; + ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; + ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; + ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; + ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; + ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; + ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; + ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; + ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; + ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; + ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; + ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; + ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; + ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; + ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; + ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; + ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; + ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; + ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; + ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; + ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; + ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; + ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; + ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; + ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; +#endif + + a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); + + for (t = 0; t < 20; t++) { + s = t & 0x0f; + if (t >= 16) + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + + tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 20; t < 40; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 40; t < 60; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 60; t < 80; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + + H(0) = H(0) + a; + H(1) = H(1) + b; + H(2) = H(2) + c; + H(3) = H(3) + d; + H(4) = H(4) + e; + + bzero(&ctxt->m.b8[0], 64); +} + +/*------------------------------------------------------------*/ + +static void +sha1_init(struct sha1_ctxt *ctxt) +{ + bzero(ctxt, sizeof(struct sha1_ctxt)); + H(0) = 0x67452301; + H(1) = 0xefcdab89; + H(2) = 0x98badcfe; + H(3) = 0x10325476; + H(4) = 0xc3d2e1f0; +} + +void +sha1_pad(struct sha1_ctxt *ctxt) +{ + size_t padlen; /*pad length in bytes*/ + size_t padstart; + + PUTPAD(0x80); + + padstart = COUNT % 64; + padlen = 64 - padstart; + if (padlen < 8) { + bzero(&ctxt->m.b8[padstart], padlen); + COUNT += padlen; + COUNT %= 64; + sha1_step(ctxt); + padstart = COUNT % 64; /* should be 0 */ + padlen = 64 - padstart; /* should be 64 */ + } + bzero(&ctxt->m.b8[padstart], padlen - 8); + COUNT += (padlen - 8); + COUNT %= 64; +#if BYTE_ORDER == BIG_ENDIAN + PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); + PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); + PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); + PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); +#else + PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); + PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); + PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); + PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); +#endif +} + +void +sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len) +{ + size_t gaplen; + size_t gapstart; + size_t off; + size_t copysiz; + + off = 0; + + while (off < len) { + gapstart = COUNT % 64; + gaplen = 64 - gapstart; + + copysiz = (gaplen < len - off) ? gaplen : len - off; + memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz); + COUNT += copysiz; + COUNT %= 64; + ctxt->c.b64[0] += copysiz * 8; + if (COUNT % 64 == 0) + sha1_step(ctxt); + off += copysiz; + } +} + +void +sha1_result(struct sha1_ctxt *ctxt, void *digest0) +{ + unsigned char *digest; + + digest = (unsigned char *)digest0; + sha1_pad(ctxt); +#if BYTE_ORDER == BIG_ENDIAN + memcpy(digest, &ctxt->h.b8[0], 20); +#else + digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; + digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; + digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; + digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; + digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; + digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; + digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; + digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; + digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; + digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; +#endif +} + +/* + * This should look and work like the libcrypto implementation + */ + +LWS_VISIBLE unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md) +{ + struct sha1_ctxt ctx; + + sha1_init(&ctx); + sha1_loop(&ctx, d, n); + sha1_result(&ctx, (void *)md); + + return md; +} + +#endif /*unsupported*/ |