Merge pull request #1036 from heinrich5991/pr_ddnet_cmake_websockets

Try to find `libwebsockets` on the host system
This commit is contained in:
Dennis Felsing 2018-02-14 14:02:57 +01:00 committed by GitHub
commit 9ec8e16ec6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 71 additions and 11848 deletions

View file

@ -282,6 +282,13 @@ find_package(PythonInterp)
find_package(SDL2) find_package(SDL2)
find_package(Threads) find_package(Threads)
find_package(Wavpack) find_package(Wavpack)
if(WEBSOCKETS)
find_package(Websockets)
else()
set(WEBSOCKETS_LIBRARIES)
set(WEBSOCKETS_INCLUDE_DIRS)
endif()
if(TARGET_OS AND TARGET_OS STREQUAL "mac") if(TARGET_OS AND TARGET_OS STREQUAL "mac")
find_program(DMG dmg) find_program(DMG dmg)
@ -338,6 +345,9 @@ show_dependency_status("PythonInterp" PYTHONINTERP)
show_dependency_status("SDL2" SDL2) show_dependency_status("SDL2" SDL2)
show_dependency_status("Wavpack" WAVPACK) show_dependency_status("Wavpack" WAVPACK)
show_dependency_status("Zlib" ZLIB) show_dependency_status("Zlib" ZLIB)
if(WEBSOCKETS)
show_dependency_status("Websockets" WEBSOCKETS)
endif()
if(NOT(PYTHONINTERP_FOUND)) if(NOT(PYTHONINTERP_FOUND))
message(SEND_ERROR "You must install Python to compile DDNet") message(SEND_ERROR "You must install Python to compile DDNet")
@ -347,6 +357,10 @@ if(MYSQL AND NOT(MYSQL_FOUND))
message(SEND_ERROR "You must install MySQL to compile the DDNet server with MySQL support") message(SEND_ERROR "You must install MySQL to compile the DDNet server with MySQL support")
endif() endif()
if(WEBSOCKETS AND NOT(WEBSOCKETS_FOUND))
message(SEND_ERROR "You must install libwebsockets to compile the DDNet server with websocket support")
endif()
if(CLIENT AND NOT(CURL_FOUND)) if(CLIENT AND NOT(CURL_FOUND))
message(SEND_ERROR "You must install Curl to compile the DDNet client") message(SEND_ERROR "You must install Curl to compile the DDNet client")
endif() endif()
@ -664,45 +678,10 @@ add_library(md5 EXCLUDE_FROM_ALL OBJECT ${DEP_MD5_SRC})
set(DEP_MD5 $<TARGET_OBJECTS:md5>) set(DEP_MD5 $<TARGET_OBJECTS:md5>)
list(APPEND TARGETS_DEP md5) list(APPEND TARGETS_DEP md5)
if(WEBSOCKETS) set(DEPS ${DEP_MD5} ${ZLIB_DEP})
set_glob(DEP_WEBSOCKETS_SRC GLOB src/engine/external/libwebsockets
alloc.c
base64-decode.c
config.h
context.c
extension-deflate-frame.c
extension-deflate-frame.h
extension-deflate-stream.c
extension-deflate-stream.h
extension.c
getifaddrs.h
handshake.c
huftable.h
lextable-strings.h
lextable.h
libwebsockets.c
libwebsockets.h
lws-plat-unix.c
output.c
parsers.c
pollfd.c
private-libwebsockets.h
server-handshake.c
server.c
service.c
sha-1.c
)
add_library(websockets EXCLUDE_FROM_ALL OBJECT ${DEP_WEBSOCKETS_SRC})
list(APPEND TARGETS_DEP websockets)
set(DEP_WEBSOCKETS $<TARGET_OBJECTS:websockets>)
else()
set(DEP_WEBSOCKETS)
endif()
set(DEPS ${DEP_MD5} ${DEP_WEBSOCKETS} ${ZLIB_DEP})
# Libraries # Libraries
set(LIBS ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES} ${PLATFORM_LIBS}) set(LIBS ${CMAKE_THREAD_LIBS_INIT} ${WEBSOCKETS_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_LIBS})
# Targets # Targets
add_library(engine-shared EXCLUDE_FROM_ALL OBJECT ${ENGINE_INTERFACE} ${ENGINE_SHARED} ${ENGINE_GENERATED_SHARED} ${BASE}) add_library(engine-shared EXCLUDE_FROM_ALL OBJECT ${ENGINE_INTERFACE} ${ENGINE_SHARED} ${ENGINE_GENERATED_SHARED} ${BASE})
@ -1511,6 +1490,7 @@ foreach(target ${TARGETS_OWN})
target_compile_definitions(${target} PRIVATE GLEW_STATIC) target_compile_definitions(${target} PRIVATE GLEW_STATIC)
if(WEBSOCKETS) if(WEBSOCKETS)
target_compile_definitions(${target} PRIVATE CONF_WEBSOCKETS) target_compile_definitions(${target} PRIVATE CONF_WEBSOCKETS)
target_include_directories(${target} PRIVATE ${WEBSOCKETS_INCLUDE_DIRS})
endif() endif()
if(MYSQL) if(MYSQL)
target_compile_definitions(${target} PRIVATE CONF_SQL) target_compile_definitions(${target} PRIVATE CONF_SQL)

View file

@ -0,0 +1,31 @@
if(NOT CMAKE_CROSSCOMPILING)
find_package(PkgConfig QUIET)
pkg_check_modules(PC_WEBSOCKETS libwebsockets)
endif()
set_extra_dirs_lib(WEBSOCKETS websockets)
find_library(WEBSOCKETS_LIBRARY
NAMES websockets
HINTS ${HINTS_WEBSOCKETS_LIBDIR} ${PC_WEBSOCKETS_LIBDIR} ${PC_WEBSOCKETS_LIBRARY_DIRS}
PATHS ${PATHS_WEBSOCKETS_LIBDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
set_extra_dirs_include(WEBSOCKETS websockets "${WEBSOCKETS_LIBRARY}")
find_path(WEBSOCKETS_INCLUDEDIR
NAMES libwebsockets.h
HINTS ${HINTS_WEBSOCKETS_INCLUDEDIR} ${PC_WEBSOCKETS_INCLUDEDIR} ${PC_WEBSOCKETS_INCLUDE_DIRS}
PATHS ${PATHS_WEBSOCKETS_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Websockets DEFAULT_MSG WEBSOCKETS_LIBRARY WEBSOCKETS_INCLUDEDIR)
mark_as_advanced(WEBSOCKETS_LIBRARY WEBSOCKETS_INCLUDEDIR)
if(WEBSOCKETS_FOUND)
set(WEBSOCKETS_LIBRARIES ${WEBSOCKETS_LIBRARY})
set(WEBSOCKETS_INCLUDE_DIRS ${WEBSOCKETS_INCLUDEDIR})
is_bundled(WEBSOCKETS_BUNDLED "${WEBSOCKETS_LIBRARY}")
endif()

View file

@ -1,526 +0,0 @@
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!

View file

@ -1,30 +0,0 @@
#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;
}

View file

@ -1,185 +0,0 @@
/*
* 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;
}

View file

@ -1,174 +0,0 @@
/* 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 */

View file

@ -1,337 +0,0 @@
/*
* 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);
}

View file

@ -1,288 +0,0 @@
#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;
}

View file

@ -1,25 +0,0 @@
#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);

View file

@ -1,166 +0,0 @@
#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;
}

View file

@ -1,20 +0,0 @@
#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);

View file

@ -1,208 +0,0 @@
#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;
}

View file

@ -1,76 +0,0 @@
#if HAVE_GETIFADDRS
#include <sys/types.h>
#include <ifaddrs.h>
#else
#ifdef __cplusplus
extern "C" {
#endif
/*
* Copyright (c) 2000 Kungliga Tekniska H<EFBFBD>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

View file

@ -1,232 +0,0 @@
/*
* 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;
}

View file

@ -1,530 +0,0 @@
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

View file

@ -1,86 +0,0 @@
/* 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 */
};

View file

@ -1,745 +0,0 @@
/* 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 */

View file

@ -1,850 +0,0 @@
/*
* 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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,442 +0,0 @@
#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

View file

@ -1,606 +0,0 @@
/*
* 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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,293 +0,0 @@
/*
* 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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,274 +0,0 @@
/*
* 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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,636 +0,0 @@
/*
* 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);
}

View file

@ -1,301 +0,0 @@
/*
* 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*/

View file

@ -3,7 +3,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "engine/external/libwebsockets/libwebsockets.h" #include <libwebsockets.h>
#include "base/system.h" #include "base/system.h"
#include "protocol.h" #include "protocol.h"
#include "ringbuffer.h" #include "ringbuffer.h"
@ -31,7 +31,7 @@ typedef struct
struct per_session_data struct per_session_data
{ {
struct libwebsocket *wsi; struct lws *wsi;
int port; int port;
sockaddr_in addr; sockaddr_in addr;
TSendBuffer send_buffer; TSendBuffer send_buffer;
@ -39,7 +39,7 @@ struct per_session_data
struct context_data struct context_data
{ {
libwebsocket_context *context; lws_context *context;
per_session_data *port_map[WS_CLIENTS]; per_session_data *port_map[WS_CLIENTS];
TRecvBuffer recv_buffer; TRecvBuffer recv_buffer;
int last_used_port; int last_used_port;
@ -57,10 +57,11 @@ static int receive_chunk(context_data *ctx_data, struct per_session_data *pss, v
return 0; return 0;
} }
static int websocket_callback(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) static int websocket_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{ {
struct per_session_data *pss = (struct per_session_data *)user; struct per_session_data *pss = (struct per_session_data *)user;
context_data *ctx_data = (context_data *)libwebsocket_context_user(context); lws_context *context = lws_get_context(wsi);
context_data *ctx_data = (context_data *)lws_context_user(context);
switch(reason) switch(reason)
{ {
@ -85,7 +86,7 @@ static int websocket_callback(struct libwebsocket_context *context, struct libwe
} }
ctx_data->last_used_port = port; ctx_data->last_used_port = port;
pss->wsi = wsi; pss->wsi = wsi;
int fd = libwebsocket_get_socket_fd(wsi); int fd = lws_get_socket_fd(wsi);
socklen_t addr_size = sizeof(pss->addr); socklen_t addr_size = sizeof(pss->addr);
getpeername(fd, (struct sockaddr *)&pss->addr, &addr_size); getpeername(fd, (struct sockaddr *)&pss->addr, &addr_size);
int orig_port = ntohs(pss->addr.sin_port); int orig_port = ntohs(pss->addr.sin_port);
@ -117,17 +118,17 @@ static int websocket_callback(struct libwebsocket_context *context, struct libwe
if(chunk == NULL) if(chunk == NULL)
break; break;
int len = chunk->size - chunk->read; int len = chunk->size - chunk->read;
int n = libwebsocket_write(wsi, &chunk->data[LWS_SEND_BUFFER_PRE_PADDING + chunk->read], chunk->size - chunk->read, LWS_WRITE_BINARY); int n = lws_write(wsi, &chunk->data[LWS_SEND_BUFFER_PRE_PADDING + chunk->read], chunk->size - chunk->read, LWS_WRITE_BINARY);
if(n < 0) if(n < 0)
return 1; return 1;
if(n < len) if(n < len)
{ {
chunk->read += n; chunk->read += n;
libwebsocket_callback_on_writable(context, wsi); lws_callback_on_writable(wsi);
break; break;
} }
pss->send_buffer.PopFirst(); pss->send_buffer.PopFirst();
libwebsocket_callback_on_writable(context, wsi); lws_callback_on_writable(wsi);
} }
break; break;
@ -145,7 +146,7 @@ static int websocket_callback(struct libwebsocket_context *context, struct libwe
return 0; return 0;
} }
static struct libwebsocket_protocols protocols[] = { { static struct lws_protocols protocols[] = { {
"binary", /* name */ "binary", /* name */
websocket_callback, /* callback */ websocket_callback, /* callback */
sizeof(struct per_session_data) /* per_session_data_size */ sizeof(struct per_session_data) /* per_session_data_size */
@ -182,7 +183,7 @@ int websocket_create(const char *addr, int port)
context_data *ctx_data = &contexts[first_free]; context_data *ctx_data = &contexts[first_free];
info.user = (void *)ctx_data; info.user = (void *)ctx_data;
ctx_data->context = libwebsocket_create_context(&info); ctx_data->context = lws_create_context(&info);
if(ctx_data->context == NULL) if(ctx_data->context == NULL)
{ {
return -1; return -1;
@ -195,23 +196,23 @@ int websocket_create(const char *addr, int port)
int websocket_destroy(int socket) int websocket_destroy(int socket)
{ {
libwebsocket_context *context = contexts[socket].context; lws_context *context = contexts[socket].context;
if(context == NULL) if(context == NULL)
return -1; return -1;
libwebsocket_context_destroy(context); lws_context_destroy(context);
contexts[socket].context = NULL; contexts[socket].context = NULL;
return 0; return 0;
} }
int websocket_recv(int socket, unsigned char *data, size_t maxsize, struct sockaddr_in *sockaddrbuf, size_t fromLen) int websocket_recv(int socket, unsigned char *data, size_t maxsize, struct sockaddr_in *sockaddrbuf, size_t fromLen)
{ {
libwebsocket_context *context = contexts[socket].context; lws_context *context = contexts[socket].context;
if(context == NULL) if(context == NULL)
return -1; return -1;
int n = libwebsocket_service(context, 0); int n = lws_service(context, 0);
if(n < 0) if(n < 0)
return n; return n;
context_data *ctx_data = (context_data *)libwebsocket_context_user(context); context_data *ctx_data = (context_data *)lws_context_user(context);
websocket_chunk *chunk = (websocket_chunk *)ctx_data->recv_buffer.First(); websocket_chunk *chunk = (websocket_chunk *)ctx_data->recv_buffer.First();
if(chunk == 0) if(chunk == 0)
return 0; return 0;
@ -234,10 +235,10 @@ int websocket_recv(int socket, unsigned char *data, size_t maxsize, struct socka
int websocket_send(int socket, const unsigned char *data, size_t size, int port) int websocket_send(int socket, const unsigned char *data, size_t size, int port)
{ {
libwebsocket_context *context = contexts[socket].context; lws_context *context = contexts[socket].context;
if(context == NULL) if(context == NULL)
return -1; return -1;
context_data *ctx_data = (context_data *)libwebsocket_context_user(context); context_data *ctx_data = (context_data *)lws_context_user(context);
struct per_session_data *pss = ctx_data->port_map[port]; struct per_session_data *pss = ctx_data->port_map[port];
if(pss == NULL) if(pss == NULL)
return -1; return -1;
@ -248,23 +249,23 @@ int websocket_send(int socket, const unsigned char *data, size_t size, int port)
chunk->read = 0; chunk->read = 0;
memcpy(&chunk->addr, &pss->addr, sizeof(sockaddr_in)); memcpy(&chunk->addr, &pss->addr, sizeof(sockaddr_in));
memcpy(&chunk->data[LWS_SEND_BUFFER_PRE_PADDING], data, size); memcpy(&chunk->data[LWS_SEND_BUFFER_PRE_PADDING], data, size);
libwebsocket_callback_on_writable(context, pss->wsi); lws_callback_on_writable(pss->wsi);
return size; return size;
} }
int websocket_fd_set(int socket, fd_set *set) int websocket_fd_set(int socket, fd_set *set)
{ {
libwebsocket_context *context = contexts[socket].context; lws_context *context = contexts[socket].context;
if(context == NULL) if(context == NULL)
return -1; return -1;
context_data *ctx_data = (context_data *)libwebsocket_context_user(context); context_data *ctx_data = (context_data *)lws_context_user(context);
int max = 0; int max = 0;
for(int i = 0; i < WS_CLIENTS; i++) for(int i = 0; i < WS_CLIENTS; i++)
{ {
per_session_data *pss = ctx_data->port_map[i]; per_session_data *pss = ctx_data->port_map[i];
if(pss == NULL) if(pss == NULL)
continue; continue;
int fd = libwebsocket_get_socket_fd(pss->wsi); int fd = lws_get_socket_fd(pss->wsi);
if(fd > max) if(fd > max)
max = fd; max = fd;
FD_SET(fd, set); FD_SET(fd, set);