Remove libwebsocket. No longer used, yay!
This commit is contained in:
parent
9e303ef71c
commit
aae6c075aa
563
COPYRIGHT.txt
563
COPYRIGHT.txt
|
@ -228,11 +228,6 @@ Comment: WebP codec
|
|||
Copyright: 2010, Google Inc.
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: ./thirdparty/libwebsockets/
|
||||
Comment: libwebsockets
|
||||
Copyright: 2010-2018, Andy Green
|
||||
License: LGPL-2.1+SLE (libwebsockets)
|
||||
|
||||
Files: ./thirdparty/mbedtls/
|
||||
Comment: Mbed TLS
|
||||
Copyright: 2006-2018, Arm Limited (or its affiliates)
|
||||
|
@ -1057,564 +1052,6 @@ License: FTL
|
|||
Robert Wilhelm <robert.wilhelm@freetype.org>
|
||||
Werner Lemberg <werner.lemberg@freetype.org>
|
||||
|
||||
License: LGPL-2.1+SLE (libwebsockets)
|
||||
Libwebsockets and included programs are provided under the terms of the GNU
|
||||
Library General Public License (LGPL) 2.1, with the following exceptions:
|
||||
.
|
||||
1) Any reference, whether in these modifications or in the GNU
|
||||
Library General Public License 2.1, to this License, these terms, the
|
||||
GNU Lesser Public License, GNU Library General Public License, LGPL, or
|
||||
any similar reference shall refer to the GNU Library General Public
|
||||
License 2.1 as modified by these paragraphs 1) through 4).
|
||||
.
|
||||
2) 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.
|
||||
.
|
||||
3) 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
|
||||
(https://libwebsockets.org)"
|
||||
.
|
||||
4) Some sources included have their own, more liberal licenses, or options
|
||||
to get original sources with the liberal terms.
|
||||
.
|
||||
Original liberal license retained
|
||||
.
|
||||
- lib/misc/sha-1.c - 3-clause BSD license retained, link to original
|
||||
- win32port/zlib - ZLIB license (see zlib.h)
|
||||
- lib/tls/mbedtls/wrapper - Apache 2.0 (only built if linked against mbedtls)
|
||||
.
|
||||
Relicensed to libwebsocket license
|
||||
.
|
||||
- lib/misc/base64-decode.c - relicensed to LGPL2.1+SLE, link to original
|
||||
- lib/misc/daemonize.c - relicensed from Public Domain to LGPL2.1+SLE,
|
||||
link to original Public Domain version
|
||||
.
|
||||
Public Domain (CC-zero) to simplify reuse
|
||||
.
|
||||
- test-apps/*.c
|
||||
- test-apps/*.h
|
||||
- minimal-examples/*
|
||||
- lwsws/*
|
||||
.
|
||||
------ end of exceptions
|
||||
.
|
||||
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!
|
||||
|
||||
License: MPL-2.0
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
|
|
@ -145,7 +145,7 @@ opts.Add(BoolVariable('builtin_libtheora', "Use the built-in libtheora library",
|
|||
opts.Add(BoolVariable('builtin_libvorbis', "Use the built-in libvorbis library", True))
|
||||
opts.Add(BoolVariable('builtin_libvpx', "Use the built-in libvpx library", True))
|
||||
opts.Add(BoolVariable('builtin_libwebp', "Use the built-in libwebp library", True))
|
||||
opts.Add(BoolVariable('builtin_libwebsockets', "Use the built-in libwebsockets library", True))
|
||||
opts.Add(BoolVariable('builtin_wslay', "Use the built-in wslay library", True))
|
||||
opts.Add(BoolVariable('builtin_mbedtls', "Use the built-in mbedTLS library", True))
|
||||
opts.Add(BoolVariable('builtin_miniupnpc', "Use the built-in miniupnpc library", True))
|
||||
opts.Add(BoolVariable('builtin_opus', "Use the built-in Opus library", True))
|
||||
|
|
|
@ -7,89 +7,7 @@ Import('env_modules')
|
|||
|
||||
env_ws = env_modules.Clone()
|
||||
|
||||
if env['builtin_libwebsockets'] and not env["platform"] == "javascript": # already builtin for javascript
|
||||
thirdparty_dir = "#thirdparty/libwebsockets/"
|
||||
helper_dir = "win32helpers/"
|
||||
thirdparty_sources = [
|
||||
|
||||
"core/alloc.c",
|
||||
"core/context.c",
|
||||
"core/libwebsockets.c",
|
||||
"core/output.c",
|
||||
"core/pollfd.c",
|
||||
"core/service.c",
|
||||
|
||||
"event-libs/poll/poll.c",
|
||||
|
||||
"misc/base64-decode.c",
|
||||
"misc/lejp.c",
|
||||
"misc/sha-1.c",
|
||||
|
||||
"roles/h1/ops-h1.c",
|
||||
"roles/http/header.c",
|
||||
"roles/http/client/client.c",
|
||||
"roles/http/client/client-handshake.c",
|
||||
"roles/http/server/fops-zip.c",
|
||||
"roles/http/server/lejp-conf.c",
|
||||
"roles/http/server/parsers.c",
|
||||
"roles/http/server/server.c",
|
||||
"roles/listen/ops-listen.c",
|
||||
"roles/pipe/ops-pipe.c",
|
||||
"roles/raw/ops-raw.c",
|
||||
|
||||
"roles/ws/client-ws.c",
|
||||
"roles/ws/client-parser-ws.c",
|
||||
"roles/ws/ops-ws.c",
|
||||
"roles/ws/server-ws.c",
|
||||
|
||||
"tls/tls.c",
|
||||
"tls/tls-client.c",
|
||||
"tls/tls-server.c",
|
||||
|
||||
"tls/mbedtls/wrapper/library/ssl_cert.c",
|
||||
"tls/mbedtls/wrapper/library/ssl_pkey.c",
|
||||
"tls/mbedtls/wrapper/library/ssl_stack.c",
|
||||
"tls/mbedtls/wrapper/library/ssl_methods.c",
|
||||
"tls/mbedtls/wrapper/library/ssl_lib.c",
|
||||
"tls/mbedtls/wrapper/library/ssl_x509.c",
|
||||
"tls/mbedtls/wrapper/platform/ssl_port.c",
|
||||
"tls/mbedtls/wrapper/platform/ssl_pm.c",
|
||||
"tls/mbedtls/lws-genhash.c",
|
||||
"tls/mbedtls/mbedtls-client.c",
|
||||
"tls/mbedtls/lws-genrsa.c",
|
||||
"tls/mbedtls/ssl.c",
|
||||
"tls/mbedtls/mbedtls-server.c"
|
||||
]
|
||||
|
||||
if env["platform"] == "android": # Builtin getifaddrs
|
||||
thirdparty_sources += ["misc/getifaddrs.c"]
|
||||
|
||||
if env["platform"] == "windows" or env["platform"] == "uwp": # Winsock
|
||||
thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"]
|
||||
else: # Unix socket
|
||||
thirdparty_sources += ["plat/lws-plat-unix.c"]
|
||||
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_lws.Prepend(CPPPATH=[thirdparty_dir])
|
||||
|
||||
if env['builtin_mbedtls']:
|
||||
mbedtls_includes = "#thirdparty/mbedtls/include"
|
||||
env_lws.Prepend(CPPPATH=[mbedtls_includes])
|
||||
|
||||
wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]]
|
||||
env_lws.Prepend(CPPPATH=wrapper_includes)
|
||||
|
||||
if env["platform"] == "windows" or env["platform"] == "uwp":
|
||||
env_lws.Prepend(CPPPATH=[thirdparty_dir + helper_dir])
|
||||
|
||||
if env["platform"] == "uwp":
|
||||
env_lws.Append(CPPDEFINES=["LWS_MINGW_SUPPORT"])
|
||||
|
||||
env_thirdparty = env_lws.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
|
||||
|
||||
if env['builtin_wslay'] and not env["platform"] == "javascript": # already builtin for javascript
|
||||
wslay_dir = "#thirdparty/wslay/"
|
||||
wslay_sources = [
|
||||
"wslay_net.c",
|
||||
|
@ -100,11 +18,11 @@ if env['builtin_libwebsockets'] and not env["platform"] == "javascript": # alrea
|
|||
]
|
||||
wslay_sources = [wslay_dir + s for s in wslay_sources]
|
||||
env_ws.Prepend(CPPPATH=[wslay_dir + "includes/"])
|
||||
env_ws.Append(CPPFLAGS=["-DHAVE_CONFIG_H"])
|
||||
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
|
||||
if env["platform"] == "windows" or env["platform"] == "uwp":
|
||||
env_ws.Append(CPPFLAGS=["-DHAVE_WINSOCK2_H"])
|
||||
env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
|
||||
else:
|
||||
env_ws.Append(CPPFLAGS=["-DHAVE_NETINET_IN_H"])
|
||||
env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
|
||||
env_wslay = env_ws.Clone()
|
||||
env_wslay.disable_warnings()
|
||||
env_wslay.add_source_files(env.modules_sources, wslay_sources)
|
||||
|
|
|
@ -1,248 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_client.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "lws_client.h"
|
||||
#include "core/io/ip.h"
|
||||
#include "core/project_settings.h"
|
||||
#if defined(LWS_OPENSSL_SUPPORT)
|
||||
#include "core/io/stream_peer_ssl.h"
|
||||
#include "tls/mbedtls/wrapper/include/openssl/ssl.h"
|
||||
#endif
|
||||
|
||||
Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
|
||||
|
||||
ERR_FAIL_COND_V(context != NULL, FAILED);
|
||||
|
||||
IP_Address addr;
|
||||
|
||||
if (!p_host.is_valid_ip_address()) {
|
||||
addr = IP::get_singleton()->resolve_hostname(p_host);
|
||||
} else {
|
||||
addr = p_host;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(!addr.is_valid(), ERR_INVALID_PARAMETER);
|
||||
|
||||
// Prepare protocols
|
||||
_lws_make_protocols(this, &LWSClient::_lws_gd_callback, p_protocols, &_lws_ref);
|
||||
|
||||
// Init lws client
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_client_connect_info i;
|
||||
|
||||
memset(&i, 0, sizeof i);
|
||||
memset(&info, 0, sizeof info);
|
||||
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = _lws_ref->lws_structs;
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
//info.ws_ping_pong_interval = 5;
|
||||
info.user = _lws_ref;
|
||||
#if defined(LWS_OPENSSL_SUPPORT)
|
||||
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
#endif
|
||||
context = lws_create_context(&info);
|
||||
|
||||
if (context == NULL) {
|
||||
_lws_free_ref(_lws_ref);
|
||||
_lws_ref = NULL;
|
||||
ERR_EXPLAIN("Unable to create lws context");
|
||||
ERR_FAIL_V(FAILED);
|
||||
}
|
||||
|
||||
i.context = context;
|
||||
if (p_protocols.size() > 0)
|
||||
i.protocol = _lws_ref->lws_names;
|
||||
else
|
||||
i.protocol = NULL;
|
||||
|
||||
if (p_ssl) {
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
if (!verify_ssl)
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
} else {
|
||||
i.ssl_connection = 0;
|
||||
}
|
||||
|
||||
// These CharStrings needs to survive till we call lws_client_connect_via_info
|
||||
CharString addr_ch = ((String)addr).ascii();
|
||||
CharString host_ch = p_host.utf8();
|
||||
CharString path_ch = p_path.utf8();
|
||||
i.address = addr_ch.get_data();
|
||||
i.host = host_ch.get_data();
|
||||
i.path = path_ch.get_data();
|
||||
i.port = p_port;
|
||||
|
||||
lws_client_connect_via_info(&i);
|
||||
|
||||
return OK;
|
||||
};
|
||||
|
||||
int LWSClient::get_max_packet_size() const {
|
||||
return (1 << _out_buf_size) - PROTO_SIZE;
|
||||
}
|
||||
|
||||
void LWSClient::poll() {
|
||||
|
||||
_lws_poll();
|
||||
}
|
||||
|
||||
int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
|
||||
|
||||
Ref<LWSPeer> peer = static_cast<Ref<LWSPeer> >(_peer);
|
||||
LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user;
|
||||
|
||||
switch (reason) {
|
||||
#if defined(LWS_OPENSSL_SUPPORT)
|
||||
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: {
|
||||
PoolByteArray arr = StreamPeerSSL::get_project_cert_array();
|
||||
if (arr.size() > 0)
|
||||
SSL_CTX_add_client_CA((SSL_CTX *)user, d2i_X509(NULL, &arr.read()[0], arr.size()));
|
||||
else if (verify_ssl)
|
||||
WARN_PRINTS("No CA cert specified in project settings, SSL will not work");
|
||||
} break;
|
||||
#endif
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
|
||||
peer_data->peer_id = 0;
|
||||
peer_data->force_close = false;
|
||||
peer_data->clean_close = false;
|
||||
_on_connect(lws_get_protocol(wsi)->name);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
_on_error();
|
||||
destroy_context();
|
||||
return -1; // We should close the connection (would probably happen anyway)
|
||||
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: {
|
||||
int code;
|
||||
String reason2 = peer->get_close_reason(in, len, code);
|
||||
peer_data->clean_close = true;
|
||||
_on_close_request(code, reason2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
peer->close();
|
||||
destroy_context();
|
||||
_on_disconnect(peer_data->clean_close);
|
||||
return 0; // We can end here
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
peer->read_wsi(in, len);
|
||||
if (peer->get_available_packet_count() > 0)
|
||||
_on_peer_packet();
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
if (peer_data->force_close) {
|
||||
peer->send_close_status(wsi);
|
||||
return -1;
|
||||
}
|
||||
|
||||
peer->write_wsi();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ref<WebSocketPeer> LWSClient::get_peer(int p_peer_id) const {
|
||||
|
||||
return _peer;
|
||||
}
|
||||
|
||||
NetworkedMultiplayerPeer::ConnectionStatus LWSClient::get_connection_status() const {
|
||||
|
||||
if (context == NULL)
|
||||
return CONNECTION_DISCONNECTED;
|
||||
|
||||
if (_peer->is_connected_to_host())
|
||||
return CONNECTION_CONNECTED;
|
||||
|
||||
return CONNECTION_CONNECTING;
|
||||
}
|
||||
|
||||
void LWSClient::disconnect_from_host(int p_code, String p_reason) {
|
||||
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
_peer->close(p_code, p_reason);
|
||||
};
|
||||
|
||||
IP_Address LWSClient::get_connected_host() const {
|
||||
|
||||
return IP_Address();
|
||||
};
|
||||
|
||||
uint16_t LWSClient::get_connected_port() const {
|
||||
|
||||
return 1025;
|
||||
};
|
||||
|
||||
Error LWSClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
|
||||
ERR_EXPLAIN("Buffers sizes can only be set before listening or connecting");
|
||||
ERR_FAIL_COND_V(context != NULL, FAILED);
|
||||
|
||||
_in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
|
||||
_in_pkt_size = nearest_shift(p_in_packets - 1);
|
||||
_out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
|
||||
_out_pkt_size = nearest_shift(p_out_packets - 1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
LWSClient::LWSClient() {
|
||||
_in_buf_size = nearest_shift((int)GLOBAL_GET(WSC_IN_BUF) - 1) + 10;
|
||||
_in_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_IN_PKT) - 1);
|
||||
_out_buf_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_BUF) - 1) + 10;
|
||||
_out_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_PKT) - 1);
|
||||
|
||||
context = NULL;
|
||||
_lws_ref = NULL;
|
||||
_peer = Ref<LWSPeer>(memnew(LWSPeer));
|
||||
};
|
||||
|
||||
LWSClient::~LWSClient() {
|
||||
|
||||
invalidate_lws_ref(); // We do not want any more callback
|
||||
disconnect_from_host();
|
||||
destroy_context();
|
||||
_peer = Ref<LWSPeer>();
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
|
@ -1,70 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_client.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef LWSCLIENT_H
|
||||
#define LWSCLIENT_H
|
||||
|
||||
#ifndef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "core/error_list.h"
|
||||
#include "lws_helper.h"
|
||||
#include "lws_peer.h"
|
||||
#include "websocket_client.h"
|
||||
|
||||
class LWSClient : public WebSocketClient {
|
||||
|
||||
GDCIIMPL(LWSClient, WebSocketClient);
|
||||
|
||||
LWS_HELPER(LWSClient);
|
||||
|
||||
private:
|
||||
int _in_buf_size;
|
||||
int _in_pkt_size;
|
||||
int _out_buf_size;
|
||||
int _out_pkt_size;
|
||||
|
||||
public:
|
||||
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
|
||||
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
|
||||
int get_max_packet_size() const;
|
||||
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
|
||||
void disconnect_from_host(int p_code = 1000, String p_reason = "");
|
||||
IP_Address get_connected_host() const;
|
||||
uint16_t get_connected_port() const;
|
||||
virtual ConnectionStatus get_connection_status() const;
|
||||
virtual void poll();
|
||||
|
||||
LWSClient();
|
||||
~LWSClient();
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
||||
|
||||
#endif // LWSCLIENT_H
|
|
@ -1,157 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_helper.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#if !defined(JAVASCRIPT_ENABLED)
|
||||
|
||||
#include "lws_helper.h"
|
||||
|
||||
_LWSRef *_lws_create_ref(void *obj) {
|
||||
|
||||
_LWSRef *out = (_LWSRef *)memalloc(sizeof(_LWSRef));
|
||||
out->is_destroying = false;
|
||||
out->free_context = false;
|
||||
out->is_polling = false;
|
||||
out->obj = obj;
|
||||
out->is_valid = true;
|
||||
out->lws_structs = NULL;
|
||||
out->lws_names = NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
void _lws_free_ref(_LWSRef *ref) {
|
||||
// Free strings and structs
|
||||
memfree(ref->lws_structs);
|
||||
memfree(ref->lws_names);
|
||||
// Free ref
|
||||
memfree(ref);
|
||||
}
|
||||
|
||||
bool _lws_destroy(struct lws_context *context, _LWSRef *ref) {
|
||||
if (context == NULL || ref->is_destroying)
|
||||
return false;
|
||||
|
||||
if (ref->is_polling) {
|
||||
ref->free_context = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ref->is_destroying = true;
|
||||
lws_context_destroy(context);
|
||||
_lws_free_ref(ref);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _lws_poll(struct lws_context *context, _LWSRef *ref) {
|
||||
|
||||
ERR_FAIL_COND_V(context == NULL, false);
|
||||
ERR_FAIL_COND_V(ref == NULL, false);
|
||||
|
||||
ref->is_polling = true;
|
||||
lws_service(context, 0);
|
||||
ref->is_polling = false;
|
||||
|
||||
if (!ref->free_context)
|
||||
return false; // Nothing to do
|
||||
|
||||
bool is_valid = ref->is_valid; // Might have been destroyed by poll
|
||||
|
||||
_lws_destroy(context, ref); // Will destroy context and ref
|
||||
|
||||
return is_valid; // If the object should NULL its context and ref
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the protocol_structs to be fed to context.
|
||||
* Also prepare the protocol string used by the client.
|
||||
*/
|
||||
void _lws_make_protocols(void *p_obj, lws_callback_function *p_callback, PoolVector<String> p_names, _LWSRef **r_lws_ref) {
|
||||
// The input strings might go away after this call, we need to copy them.
|
||||
// We will clear them when destroying the context.
|
||||
int i;
|
||||
int len = p_names.size();
|
||||
size_t data_size = sizeof(struct LWSPeer::PeerData);
|
||||
PoolVector<String>::Read pnr = p_names.read();
|
||||
|
||||
// This is a reference connecting the object with lws keep track of status, mallocs, etc.
|
||||
// Must survive as long the context.
|
||||
// Must be freed manually when context creation fails.
|
||||
_LWSRef *ref = _lws_create_ref(p_obj);
|
||||
|
||||
// LWS protocol structs.
|
||||
ref->lws_structs = (struct lws_protocols *)memalloc(sizeof(struct lws_protocols) * (len + 2));
|
||||
memset(ref->lws_structs, 0, sizeof(struct lws_protocols) * (len + 2));
|
||||
|
||||
CharString strings = p_names.join(",").ascii();
|
||||
int str_len = strings.length();
|
||||
|
||||
// Joined string of protocols, double the size: comma separated first, NULL separated last
|
||||
ref->lws_names = (char *)memalloc((str_len + 1) * 2); // Plus the terminator
|
||||
|
||||
char *names_ptr = ref->lws_names;
|
||||
struct lws_protocols *structs_ptr = ref->lws_structs;
|
||||
|
||||
// Comma separated protocols string to be used in client Sec-WebSocket-Protocol header
|
||||
if (str_len > 0)
|
||||
copymem(names_ptr, strings.get_data(), str_len);
|
||||
names_ptr[str_len] = '\0'; // NULL terminator
|
||||
|
||||
// NULL terminated protocol strings to be used in protocol structs
|
||||
if (str_len > 0)
|
||||
copymem(&names_ptr[str_len + 1], strings.get_data(), str_len);
|
||||
names_ptr[(str_len * 2) + 1] = '\0'; // NULL terminator
|
||||
int pos = str_len + 1;
|
||||
|
||||
// The first protocol is the default for any http request (before upgrade).
|
||||
// It is also used as the websocket protocol when no subprotocol is specified.
|
||||
structs_ptr[0].name = "default";
|
||||
structs_ptr[0].callback = p_callback;
|
||||
structs_ptr[0].per_session_data_size = data_size;
|
||||
structs_ptr[0].rx_buffer_size = LWS_BUF_SIZE;
|
||||
structs_ptr[0].tx_packet_size = LWS_PACKET_SIZE;
|
||||
// Add user defined protocols
|
||||
for (i = 0; i < len; i++) {
|
||||
structs_ptr[i + 1].name = (const char *)&names_ptr[pos];
|
||||
structs_ptr[i + 1].callback = p_callback;
|
||||
structs_ptr[i + 1].per_session_data_size = data_size;
|
||||
structs_ptr[i + 1].rx_buffer_size = LWS_BUF_SIZE;
|
||||
structs_ptr[i + 1].tx_packet_size = LWS_PACKET_SIZE;
|
||||
pos += pnr[i].ascii().length() + 1;
|
||||
names_ptr[pos - 1] = '\0';
|
||||
}
|
||||
// Add protocols terminator
|
||||
structs_ptr[len + 1].name = NULL;
|
||||
structs_ptr[len + 1].callback = NULL;
|
||||
structs_ptr[len + 1].per_session_data_size = 0;
|
||||
structs_ptr[len + 1].rx_buffer_size = 0;
|
||||
|
||||
*r_lws_ref = ref;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,111 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_helper.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef LWS_HELPER_H
|
||||
#define LWS_HELPER_H
|
||||
|
||||
#define LWS_BUF_SIZE 65536
|
||||
#define LWS_PACKET_SIZE LWS_BUF_SIZE
|
||||
|
||||
#include "core/io/stream_peer.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/reference.h"
|
||||
#include "core/ring_buffer.h"
|
||||
#include "lws_peer.h"
|
||||
|
||||
struct _LWSRef {
|
||||
bool free_context;
|
||||
bool is_polling;
|
||||
bool is_valid;
|
||||
bool is_destroying;
|
||||
void *obj;
|
||||
struct lws_protocols *lws_structs;
|
||||
char *lws_names;
|
||||
};
|
||||
|
||||
_LWSRef *_lws_create_ref(void *obj);
|
||||
void _lws_free_ref(_LWSRef *ref);
|
||||
bool _lws_destroy(struct lws_context *context, _LWSRef *ref);
|
||||
bool _lws_poll(struct lws_context *context, _LWSRef *ref);
|
||||
void _lws_make_protocols(void *p_obj, lws_callback_function *p_callback, PoolVector<String> p_names, _LWSRef **r_lws_ref);
|
||||
|
||||
/* clang-format off */
|
||||
#define LWS_HELPER(CNAME) \
|
||||
protected: \
|
||||
struct _LWSRef *_lws_ref; \
|
||||
struct lws_context *context; \
|
||||
bool _keep_servicing; \
|
||||
\
|
||||
static int _lws_gd_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { \
|
||||
\
|
||||
if (wsi == NULL) { \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
struct _LWSRef *ref = (struct _LWSRef *)lws_context_user(lws_get_context(wsi)); \
|
||||
if (!ref->is_valid) \
|
||||
return 0; \
|
||||
CNAME *helper = (CNAME *)ref->obj; \
|
||||
helper->_keep_servicing = true; \
|
||||
return helper->_handle_cb(wsi, reason, user, in, len); \
|
||||
} \
|
||||
\
|
||||
void invalidate_lws_ref() { \
|
||||
if (_lws_ref != NULL) \
|
||||
_lws_ref->is_valid = false; \
|
||||
} \
|
||||
\
|
||||
void destroy_context() { \
|
||||
if (_lws_destroy(context, _lws_ref)) { \
|
||||
context = NULL; \
|
||||
_lws_ref = NULL; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
virtual int _handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); \
|
||||
\
|
||||
void _lws_poll() { \
|
||||
ERR_FAIL_COND(context == NULL); \
|
||||
do { \
|
||||
_keep_servicing = false; \
|
||||
if (::_lws_poll(context, _lws_ref)) { \
|
||||
context = NULL; \
|
||||
_lws_ref = NULL; \
|
||||
break; \
|
||||
} \
|
||||
} while (_keep_servicing); \
|
||||
} \
|
||||
\
|
||||
protected:
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#endif // LWS_HELPER_H
|
|
@ -1,270 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_peer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "lws_peer.h"
|
||||
|
||||
#include "core/io/ip.h"
|
||||
|
||||
// Needed for socket_helpers on Android at least. UNIXes has it, just include if not windows
|
||||
#if !defined(WINDOWS_ENABLED)
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "drivers/unix/net_socket_posix.h"
|
||||
|
||||
void LWSPeer::set_wsi(struct lws *p_wsi, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size) {
|
||||
ERR_FAIL_COND(wsi != NULL);
|
||||
|
||||
_in_buffer.resize(p_in_pkt_size, p_in_buf_size);
|
||||
_out_buffer.resize(p_out_pkt_size, p_out_buf_size);
|
||||
_packet_buffer.resize((1 << MAX(p_in_buf_size, p_out_buf_size)) + LWS_PRE);
|
||||
wsi = p_wsi;
|
||||
};
|
||||
|
||||
void LWSPeer::set_write_mode(WriteMode p_mode) {
|
||||
write_mode = p_mode;
|
||||
}
|
||||
|
||||
LWSPeer::WriteMode LWSPeer::get_write_mode() const {
|
||||
return write_mode;
|
||||
}
|
||||
|
||||
Error LWSPeer::read_wsi(void *in, size_t len) {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
|
||||
|
||||
if (lws_is_first_fragment(wsi))
|
||||
_in_size = 0;
|
||||
else if (_in_size == -1) // Trash this frame
|
||||
return ERR_FILE_CORRUPT;
|
||||
|
||||
Error err = _in_buffer.write_packet((const uint8_t *)in, len, NULL);
|
||||
|
||||
if (err != OK) {
|
||||
_in_buffer.discard_payload(_in_size);
|
||||
_in_size = -1;
|
||||
ERR_FAIL_V(err);
|
||||
}
|
||||
|
||||
_in_size += len;
|
||||
|
||||
if (lws_is_final_fragment(wsi)) {
|
||||
uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1;
|
||||
err = _in_buffer.write_packet(NULL, _in_size, &is_string);
|
||||
if (err != OK) {
|
||||
_in_buffer.discard_payload(_in_size);
|
||||
_in_size = -1;
|
||||
ERR_FAIL_V(err);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error LWSPeer::write_wsi() {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
|
||||
|
||||
PoolVector<uint8_t> tmp;
|
||||
int count = _out_buffer.packets_left();
|
||||
|
||||
if (count == 0)
|
||||
return OK;
|
||||
|
||||
int read = 0;
|
||||
uint8_t is_string = 0;
|
||||
PoolVector<uint8_t>::Write rw = _packet_buffer.write();
|
||||
_out_buffer.read_packet(&(rw[LWS_PRE]), _packet_buffer.size() - LWS_PRE, &is_string, read);
|
||||
|
||||
enum lws_write_protocol mode = is_string ? LWS_WRITE_TEXT : LWS_WRITE_BINARY;
|
||||
lws_write(wsi, &(rw[LWS_PRE]), read, mode);
|
||||
|
||||
if (count > 1)
|
||||
lws_callback_on_writable(wsi); // we want to write more!
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error LWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
|
||||
|
||||
uint8_t is_string = write_mode == WRITE_MODE_TEXT;
|
||||
_out_buffer.write_packet(p_buffer, p_buffer_size, &is_string);
|
||||
lws_callback_on_writable(wsi); // notify that we want to write
|
||||
return OK;
|
||||
};
|
||||
|
||||
Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
|
||||
|
||||
r_buffer_size = 0;
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
|
||||
|
||||
if (_in_buffer.packets_left() == 0)
|
||||
return ERR_UNAVAILABLE;
|
||||
|
||||
int read = 0;
|
||||
PoolVector<uint8_t>::Write rw = _packet_buffer.write();
|
||||
_in_buffer.read_packet(rw.ptr(), _packet_buffer.size(), &_is_string, read);
|
||||
|
||||
*r_buffer = rw.ptr();
|
||||
r_buffer_size = read;
|
||||
|
||||
return OK;
|
||||
};
|
||||
|
||||
int LWSPeer::get_available_packet_count() const {
|
||||
|
||||
if (!is_connected_to_host())
|
||||
return 0;
|
||||
|
||||
return _in_buffer.packets_left();
|
||||
};
|
||||
|
||||
bool LWSPeer::was_string_packet() const {
|
||||
|
||||
return _is_string;
|
||||
};
|
||||
|
||||
bool LWSPeer::is_connected_to_host() const {
|
||||
|
||||
return wsi != NULL;
|
||||
};
|
||||
|
||||
String LWSPeer::get_close_reason(void *in, size_t len, int &r_code) {
|
||||
String s;
|
||||
r_code = 0;
|
||||
if (len < 2) // From docs this should not happen
|
||||
return s;
|
||||
|
||||
const uint8_t *b = (const uint8_t *)in;
|
||||
r_code = b[0] << 8 | b[1];
|
||||
|
||||
if (len > 2) {
|
||||
const char *utf8 = (const char *)&b[2];
|
||||
s.parse_utf8(utf8, len - 2);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void LWSPeer::send_close_status(struct lws *p_wsi) {
|
||||
if (close_code == -1)
|
||||
return;
|
||||
|
||||
int len = close_reason.size();
|
||||
ERR_FAIL_COND(len > 123); // Maximum allowed reason size in bytes
|
||||
|
||||
lws_close_status code = (lws_close_status)close_code;
|
||||
unsigned char *reason = len > 0 ? (unsigned char *)close_reason.utf8().ptrw() : NULL;
|
||||
|
||||
lws_close_reason(p_wsi, code, reason, len);
|
||||
|
||||
close_code = -1;
|
||||
close_reason = "";
|
||||
}
|
||||
|
||||
void LWSPeer::close(int p_code, String p_reason) {
|
||||
if (wsi != NULL) {
|
||||
close_code = p_code;
|
||||
close_reason = p_reason;
|
||||
PeerData *data = ((PeerData *)lws_wsi_user(wsi));
|
||||
data->force_close = true;
|
||||
data->clean_close = true;
|
||||
lws_callback_on_writable(wsi); // Notify that we want to disconnect
|
||||
} else {
|
||||
close_code = -1;
|
||||
close_reason = "";
|
||||
}
|
||||
wsi = NULL;
|
||||
_in_buffer.clear();
|
||||
_out_buffer.clear();
|
||||
_in_size = 0;
|
||||
_is_string = 0;
|
||||
_packet_buffer.resize(0);
|
||||
};
|
||||
|
||||
IP_Address LWSPeer::get_connected_host() const {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), IP_Address());
|
||||
|
||||
IP_Address ip;
|
||||
uint16_t port = 0;
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
|
||||
int fd = lws_get_socket_fd(wsi);
|
||||
ERR_FAIL_COND_V(fd == -1, IP_Address());
|
||||
|
||||
int ret = getpeername(fd, (struct sockaddr *)&addr, &len);
|
||||
ERR_FAIL_COND_V(ret != 0, IP_Address());
|
||||
|
||||
NetSocketPosix::_set_ip_port(&addr, ip, port);
|
||||
|
||||
return ip;
|
||||
};
|
||||
|
||||
uint16_t LWSPeer::get_connected_port() const {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), 0);
|
||||
|
||||
IP_Address ip;
|
||||
uint16_t port = 0;
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
|
||||
int fd = lws_get_socket_fd(wsi);
|
||||
ERR_FAIL_COND_V(fd == -1, 0);
|
||||
|
||||
int ret = getpeername(fd, (struct sockaddr *)&addr, &len);
|
||||
ERR_FAIL_COND_V(ret != 0, 0);
|
||||
|
||||
NetSocketPosix::_set_ip_port(&addr, ip, port);
|
||||
|
||||
return port;
|
||||
};
|
||||
|
||||
LWSPeer::LWSPeer() {
|
||||
wsi = NULL;
|
||||
write_mode = WRITE_MODE_BINARY;
|
||||
close();
|
||||
};
|
||||
|
||||
LWSPeer::~LWSPeer() {
|
||||
|
||||
close();
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
|
@ -1,96 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_peer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef LWSPEER_H
|
||||
#define LWSPEER_H
|
||||
|
||||
#ifndef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "core/error_list.h"
|
||||
#include "core/io/packet_peer.h"
|
||||
#include "core/ring_buffer.h"
|
||||
#include "libwebsockets.h"
|
||||
#include "lws_config.h"
|
||||
#include "packet_buffer.h"
|
||||
#include "websocket_peer.h"
|
||||
|
||||
class LWSPeer : public WebSocketPeer {
|
||||
|
||||
GDCIIMPL(LWSPeer, WebSocketPeer);
|
||||
|
||||
private:
|
||||
int _in_size;
|
||||
uint8_t _is_string;
|
||||
// Our packet info is just a boolean (is_string), using uint8_t for it.
|
||||
PacketBuffer<uint8_t> _in_buffer;
|
||||
PacketBuffer<uint8_t> _out_buffer;
|
||||
|
||||
PoolVector<uint8_t> _packet_buffer;
|
||||
|
||||
struct lws *wsi;
|
||||
WriteMode write_mode;
|
||||
|
||||
int close_code;
|
||||
String close_reason;
|
||||
|
||||
public:
|
||||
struct PeerData {
|
||||
uint32_t peer_id;
|
||||
bool force_close;
|
||||
bool clean_close;
|
||||
};
|
||||
|
||||
virtual int get_available_packet_count() const;
|
||||
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
|
||||
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
|
||||
virtual int get_max_packet_size() const { return _packet_buffer.size(); };
|
||||
|
||||
virtual void close(int p_code = 1000, String p_reason = "");
|
||||
virtual bool is_connected_to_host() const;
|
||||
virtual IP_Address get_connected_host() const;
|
||||
virtual uint16_t get_connected_port() const;
|
||||
|
||||
virtual WriteMode get_write_mode() const;
|
||||
virtual void set_write_mode(WriteMode p_mode);
|
||||
virtual bool was_string_packet() const;
|
||||
|
||||
void set_wsi(struct lws *wsi, unsigned int _in_buf_size, unsigned int _in_pkt_size, unsigned int _out_buf_size, unsigned int _out_pkt_size);
|
||||
Error read_wsi(void *in, size_t len);
|
||||
Error write_wsi();
|
||||
void send_close_status(struct lws *wsi);
|
||||
String get_close_reason(void *in, size_t len, int &r_code);
|
||||
|
||||
LWSPeer();
|
||||
~LWSPeer();
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
||||
|
||||
#endif // LSWPEER_H
|
|
@ -1,225 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_server.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "lws_server.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/project_settings.h"
|
||||
|
||||
Error LWSServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_api) {
|
||||
|
||||
ERR_FAIL_COND_V(context != NULL, FAILED);
|
||||
|
||||
_is_multiplayer = gd_mp_api;
|
||||
|
||||
struct lws_context_creation_info info;
|
||||
memset(&info, 0, sizeof info);
|
||||
|
||||
// Prepare lws protocol structs
|
||||
_lws_make_protocols(this, &LWSServer::_lws_gd_callback, p_protocols, &_lws_ref);
|
||||
|
||||
info.port = p_port;
|
||||
info.user = _lws_ref;
|
||||
info.protocols = _lws_ref->lws_structs;
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
//info.ws_ping_pong_interval = 5;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
|
||||
if (context == NULL) {
|
||||
_lws_free_ref(_lws_ref);
|
||||
_lws_ref = NULL;
|
||||
ERR_EXPLAIN("Unable to create LWS context");
|
||||
ERR_FAIL_V(FAILED);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool LWSServer::is_listening() const {
|
||||
return context != NULL;
|
||||
}
|
||||
|
||||
int LWSServer::get_max_packet_size() const {
|
||||
return (1 << _out_buf_size) - PROTO_SIZE;
|
||||
}
|
||||
|
||||
int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
|
||||
|
||||
LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
// no http for now
|
||||
// closing immediately returning -1;
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
||||
// check header here?
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED: {
|
||||
int32_t id = _gen_unique_id();
|
||||
|
||||
Ref<LWSPeer> peer = Ref<LWSPeer>(memnew(LWSPeer));
|
||||
peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
|
||||
_peer_map[id] = peer;
|
||||
|
||||
peer_data->peer_id = id;
|
||||
peer_data->force_close = false;
|
||||
peer_data->clean_close = false;
|
||||
_on_connect(id, lws_get_protocol(wsi)->name);
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: {
|
||||
if (peer_data == NULL)
|
||||
return 0;
|
||||
|
||||
int32_t id = peer_data->peer_id;
|
||||
if (_peer_map.has(id)) {
|
||||
int code;
|
||||
Ref<LWSPeer> peer = _peer_map[id];
|
||||
String reason2 = peer->get_close_reason(in, len, code);
|
||||
peer_data->clean_close = true;
|
||||
_on_close_request(id, code, reason2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLOSED: {
|
||||
if (peer_data == NULL)
|
||||
return 0;
|
||||
int32_t id = peer_data->peer_id;
|
||||
bool clean = peer_data->clean_close;
|
||||
if (_peer_map.has(id)) {
|
||||
_peer_map[id]->close();
|
||||
_peer_map.erase(id);
|
||||
}
|
||||
_on_disconnect(id, clean);
|
||||
return 0; // we can end here
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_RECEIVE: {
|
||||
int32_t id = peer_data->peer_id;
|
||||
if (_peer_map.has(id)) {
|
||||
static_cast<Ref<LWSPeer> >(_peer_map[id])->read_wsi(in, len);
|
||||
if (_peer_map[id]->get_available_packet_count() > 0)
|
||||
_on_peer_packet(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE: {
|
||||
int id = peer_data->peer_id;
|
||||
if (peer_data->force_close) {
|
||||
if (_peer_map.has(id)) {
|
||||
Ref<LWSPeer> peer = _peer_map[id];
|
||||
peer->send_close_status(wsi);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_peer_map.has(id))
|
||||
static_cast<Ref<LWSPeer> >(_peer_map[id])->write_wsi();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LWSServer::stop() {
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
_peer_map.clear();
|
||||
destroy_context();
|
||||
context = NULL;
|
||||
}
|
||||
|
||||
bool LWSServer::has_peer(int p_id) const {
|
||||
return _peer_map.has(p_id);
|
||||
}
|
||||
|
||||
Ref<WebSocketPeer> LWSServer::get_peer(int p_id) const {
|
||||
ERR_FAIL_COND_V(!has_peer(p_id), NULL);
|
||||
return _peer_map[p_id];
|
||||
}
|
||||
|
||||
IP_Address LWSServer::get_peer_address(int p_peer_id) const {
|
||||
ERR_FAIL_COND_V(!has_peer(p_peer_id), IP_Address());
|
||||
|
||||
return _peer_map[p_peer_id]->get_connected_host();
|
||||
}
|
||||
|
||||
int LWSServer::get_peer_port(int p_peer_id) const {
|
||||
ERR_FAIL_COND_V(!has_peer(p_peer_id), 0);
|
||||
|
||||
return _peer_map[p_peer_id]->get_connected_port();
|
||||
}
|
||||
|
||||
void LWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
|
||||
ERR_FAIL_COND(!has_peer(p_peer_id));
|
||||
|
||||
get_peer(p_peer_id)->close(p_code, p_reason);
|
||||
}
|
||||
|
||||
Error LWSServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
|
||||
ERR_EXPLAIN("Buffers sizes can only be set before listening or connecting");
|
||||
ERR_FAIL_COND_V(context != NULL, FAILED);
|
||||
|
||||
_in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
|
||||
_in_pkt_size = nearest_shift(p_in_packets - 1);
|
||||
_out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
|
||||
_out_pkt_size = nearest_shift(p_out_packets - 1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
LWSServer::LWSServer() {
|
||||
_in_buf_size = nearest_shift((int)GLOBAL_GET(WSS_IN_BUF) - 1) + 10;
|
||||
_in_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_IN_PKT) - 1);
|
||||
_out_buf_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_BUF) - 1) + 10;
|
||||
_out_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_PKT) - 1);
|
||||
context = NULL;
|
||||
_lws_ref = NULL;
|
||||
}
|
||||
|
||||
LWSServer::~LWSServer() {
|
||||
invalidate_lws_ref(); // we do not want any more callbacks
|
||||
stop();
|
||||
}
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
|
@ -1,73 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* lws_server.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef LWSSERVER_H
|
||||
#define LWSSERVER_H
|
||||
|
||||
#ifndef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "core/reference.h"
|
||||
#include "lws_helper.h"
|
||||
#include "lws_peer.h"
|
||||
#include "websocket_server.h"
|
||||
|
||||
class LWSServer : public WebSocketServer {
|
||||
|
||||
GDCIIMPL(LWSServer, WebSocketServer);
|
||||
|
||||
LWS_HELPER(LWSServer);
|
||||
|
||||
private:
|
||||
Map<int, Ref<LWSPeer> > peer_map;
|
||||
int _in_buf_size;
|
||||
int _in_pkt_size;
|
||||
int _out_buf_size;
|
||||
int _out_pkt_size;
|
||||
|
||||
public:
|
||||
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
|
||||
Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
|
||||
void stop();
|
||||
bool is_listening() const;
|
||||
int get_max_packet_size() const;
|
||||
bool has_peer(int p_id) const;
|
||||
Ref<WebSocketPeer> get_peer(int p_id) const;
|
||||
IP_Address get_peer_address(int p_peer_id) const;
|
||||
int get_peer_port(int p_peer_id) const;
|
||||
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
|
||||
virtual void poll() { _lws_poll(); }
|
||||
|
||||
LWSServer();
|
||||
~LWSServer();
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
||||
|
||||
#endif // LWSSERVER_H
|
|
@ -37,9 +37,6 @@
|
|||
#include "emws_peer.h"
|
||||
#include "emws_server.h"
|
||||
#else
|
||||
#include "lws_client.h"
|
||||
#include "lws_peer.h"
|
||||
#include "lws_server.h"
|
||||
#include "wsl_client.h"
|
||||
#include "wsl_server.h"
|
||||
#endif
|
||||
|
@ -66,9 +63,7 @@ void register_websocket_types() {
|
|||
EMWSClient::make_default();
|
||||
EMWSServer::make_default();
|
||||
#else
|
||||
LWSPeer::make_default();
|
||||
LWSClient::make_default();
|
||||
LWSServer::make_default();
|
||||
WSLPeer::make_default();
|
||||
WSLClient::make_default();
|
||||
WSLServer::make_default();
|
||||
#endif
|
||||
|
|
|
@ -128,8 +128,8 @@ def configure(env):
|
|||
if any(platform.machine() in s for s in list_of_x86):
|
||||
env["x86_libtheora_opt_gcc"] = True
|
||||
|
||||
if not env['builtin_libwebsockets']:
|
||||
env.ParseConfig('pkg-config libwebsockets --cflags --libs')
|
||||
if not env['builtin_wslay']:
|
||||
env.ParseConfig('pkg-config libwslay --cflags --libs')
|
||||
|
||||
if not env['builtin_mbedtls']:
|
||||
# mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
|
||||
|
|
|
@ -196,8 +196,8 @@ def configure(env):
|
|||
# mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
|
||||
env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
|
||||
|
||||
if not env['builtin_libwebsockets']:
|
||||
env.ParseConfig('pkg-config libwebsockets --cflags --libs')
|
||||
if not env['builtin_wslay']:
|
||||
env.ParseConfig('pkg-config libwslay --cflags --libs')
|
||||
|
||||
if not env['builtin_miniupnpc']:
|
||||
# No pkgconfig file so far, hardcode default paths.
|
||||
|
|
|
@ -266,8 +266,8 @@ def configure(env):
|
|||
# mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
|
||||
env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
|
||||
|
||||
if not env['builtin_libwebsockets']:
|
||||
env.ParseConfig('pkg-config libwebsockets --cflags --libs')
|
||||
if not env['builtin_wslay']:
|
||||
env.ParseConfig('pkg-config libwslay --cflags --libs')
|
||||
|
||||
if not env['builtin_miniupnpc']:
|
||||
# No pkgconfig file so far, hardcode default paths.
|
||||
|
|
|
@ -269,33 +269,6 @@ changes are marked with `// -- GODOT --` comments.
|
|||
- License: MIT
|
||||
|
||||
|
||||
## libwebsockets
|
||||
|
||||
- Upstream: https://github.com/warmcat/libwebsockets
|
||||
- Version: 3.0.1
|
||||
- License: LGPLv2.1 + static linking exception
|
||||
|
||||
File extracted from upstream source:
|
||||
- From `lib/` into `thirdparty/libwebsockets`:
|
||||
- Everything from `core`
|
||||
- From `event-libs` only the `poll` subfolder
|
||||
- From `misc` only `base64-decode.c`, `getifaddrs.c`, `getifaddrs.h`, `lejp.c`, and `sha-1.c`
|
||||
- From `plat` only `lws-plat-unix.c` and `lws-plat-win.c`
|
||||
- From `roles` only `private.h`, `h1`, `http`, `listen`, `pipe`, `raw`, `ws`
|
||||
- From `roles/http` exclude `minilex.c`
|
||||
- From `roles/http/server` exclude `access-log.c`, `lws-spa.c`, `ranges.c`, and `rewrite.c`
|
||||
- From `roles/ws` exclude `ext` folder.
|
||||
- From `tls` exclude `openssl` folder.
|
||||
- Also copy `win32helpers/` from `win32port/` inside `thirdparty/libwebsockets`
|
||||
- A fix has been added to allow building for 32-bits UWP, replacing `GetFileSize[Ex]` and `CreateFileW` with supported functions.
|
||||
There is a diff for this change in `thirdparty/libwebsockets/uwp_fixes.diff`
|
||||
- A fix to disable V6ONLY flag from IPv6 sockets (on by default on some systems) has been also applied.
|
||||
The diff for this change can be found in `thirdparty/libwebsockets/ipv6_fixes.diff`
|
||||
|
||||
Important: `lws_config.h` and `lws_config_private.h` contains custom
|
||||
Godot build configurations, check them out when updating.
|
||||
|
||||
|
||||
## mbedtls
|
||||
|
||||
- Upstream: https://tls.mbed.org/
|
||||
|
|
|
@ -1,556 +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) Any reference, whether in these modifications or in the GNU
|
||||
Library General Public License 2.1, to this License, these terms, the
|
||||
GNU Lesser Public License, GNU Library General Public License, LGPL, or
|
||||
any similar reference shall refer to the GNU Library General Public
|
||||
License 2.1 as modified by these paragraphs 1) through 4).
|
||||
|
||||
2) 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.
|
||||
|
||||
3) 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
|
||||
(https://libwebsockets.org)"
|
||||
|
||||
4) Some sources included have their own, more liberal licenses, or options
|
||||
to get original sources with the liberal terms.
|
||||
|
||||
Original liberal license retained
|
||||
|
||||
- lib/misc/sha-1.c - 3-clause BSD license retained, link to original
|
||||
- win32port/zlib - ZLIB license (see zlib.h)
|
||||
- lib/tls/mbedtls/wrapper - Apache 2.0 (only built if linked against mbedtls)
|
||||
|
||||
Relicensed to libwebsocket license
|
||||
|
||||
- lib/misc/base64-decode.c - relicensed to LGPL2.1+SLE, link to original
|
||||
- lib/misc/daemonize.c - relicensed from Public Domain to LGPL2.1+SLE,
|
||||
link to original Public Domain version
|
||||
|
||||
Public Domain (CC-zero) to simplify reuse
|
||||
|
||||
- test-apps/*.c
|
||||
- test-apps/*.h
|
||||
- minimal-examples/*
|
||||
- lwsws/*
|
||||
|
||||
------ end of exceptions
|
||||
|
||||
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!
|
|
@ -1,92 +0,0 @@
|
|||
#include "core/private.h"
|
||||
|
||||
#if defined(LWS_PLAT_OPTEE)
|
||||
|
||||
#define TEE_USER_MEM_HINT_NO_FILL_ZERO 0x80000000
|
||||
|
||||
void *__attribute__((weak))
|
||||
TEE_Malloc(uint32_t size, uint32_t hint)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void *__attribute__((weak))
|
||||
TEE_Realloc(void *buffer, uint32_t newSize)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void __attribute__((weak))
|
||||
TEE_Free(void *buffer)
|
||||
{
|
||||
}
|
||||
|
||||
void *lws_realloc(void *ptr, size_t size, const char *reason)
|
||||
{
|
||||
return TEE_Realloc(ptr, size);
|
||||
}
|
||||
|
||||
void *lws_malloc(size_t size, const char *reason)
|
||||
{
|
||||
return TEE_Malloc(size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
|
||||
}
|
||||
|
||||
void lws_free(void *p)
|
||||
{
|
||||
TEE_Free(p);
|
||||
}
|
||||
|
||||
void *lws_zalloc(size_t size, const char *reason)
|
||||
{
|
||||
void *ptr = TEE_Malloc(size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
|
||||
if (ptr)
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void lws_set_allocator(void *(*cb)(void *ptr, size_t size, const char *reason))
|
||||
{
|
||||
(void)cb;
|
||||
}
|
||||
#else
|
||||
|
||||
static void *_realloc(void *ptr, size_t size, const char *reason)
|
||||
{
|
||||
if (size) {
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
lwsl_notice("%s: size %lu: %s (free heap %d)\n", __func__,
|
||||
(unsigned long)size, reason, (unsigned int)esp_get_free_heap_size() - (int)size);
|
||||
#else
|
||||
lwsl_debug("%s: size %lu: %s\n", __func__,
|
||||
(unsigned long)size, reason);
|
||||
#endif
|
||||
#if defined(LWS_PLAT_OPTEE)
|
||||
return (void *)TEE_Realloc(ptr, size);
|
||||
#else
|
||||
return (void *)realloc(ptr, size);
|
||||
#endif
|
||||
}
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *(*_lws_realloc)(void *ptr, size_t size, const char *reason) = _realloc;
|
||||
|
||||
void *lws_realloc(void *ptr, size_t size, const char *reason)
|
||||
{
|
||||
return _lws_realloc(ptr, size, reason);
|
||||
}
|
||||
|
||||
void *lws_zalloc(size_t size, const char *reason)
|
||||
{
|
||||
void *ptr = _lws_realloc(NULL, size, reason);
|
||||
if (ptr)
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void lws_set_allocator(void *(*cb)(void *ptr, size_t size, const char *reason))
|
||||
{
|
||||
_lws_realloc = cb;
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,320 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
/*
|
||||
* notice this returns number of bytes consumed, or -1
|
||||
*/
|
||||
int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
size_t real_len = len;
|
||||
unsigned int n;
|
||||
|
||||
// lwsl_hexdump_err(buf, len);
|
||||
|
||||
/*
|
||||
* Detect if we got called twice without going through the
|
||||
* event loop to handle pending. This would be caused by either
|
||||
* back-to-back writes in one WRITABLE (illegal) or calling lws_write()
|
||||
* from outside the WRITABLE callback (illegal).
|
||||
*/
|
||||
if (wsi->could_have_pending) {
|
||||
lwsl_hexdump_level(LLL_ERR, buf, len);
|
||||
lwsl_err("** %p: vh: %s, prot: %s, role %s: "
|
||||
"Illegal back-to-back write of %lu detected...\n",
|
||||
wsi, wsi->vhost->name, wsi->protocol->name,
|
||||
wsi->role_ops->name,
|
||||
(unsigned long)len);
|
||||
// assert(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_WRITE, 1);
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
/* just ignore sends after we cleared the truncation buffer */
|
||||
if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE && !wsi->trunc_len)
|
||||
return (int)len;
|
||||
|
||||
if (wsi->trunc_len && (buf < wsi->trunc_alloc ||
|
||||
buf > (wsi->trunc_alloc + wsi->trunc_len + wsi->trunc_offset))) {
|
||||
lwsl_hexdump_level(LLL_ERR, buf, len);
|
||||
lwsl_err("** %p: vh: %s, prot: %s, Sending new %lu, pending truncated ...\n"
|
||||
" It's illegal to do an lws_write outside of\n"
|
||||
" the writable callback: fix your code\n",
|
||||
wsi, wsi->vhost->name, wsi->protocol->name,
|
||||
(unsigned long)len);
|
||||
assert(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!wsi->http2_substream && !lws_socket_is_valid(wsi->desc.sockfd))
|
||||
lwsl_warn("** error invalid sock but expected to send\n");
|
||||
|
||||
/* limit sending */
|
||||
if (wsi->protocol->tx_packet_size)
|
||||
n = (int)wsi->protocol->tx_packet_size;
|
||||
else {
|
||||
n = (int)wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = context->pt_serv_buf_size;
|
||||
}
|
||||
n += LWS_PRE + 4;
|
||||
if (n > len)
|
||||
n = (int)len;
|
||||
|
||||
/* nope, send it on the socket directly */
|
||||
lws_latency_pre(context, wsi);
|
||||
n = lws_ssl_capable_write(wsi, buf, n);
|
||||
lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
|
||||
|
||||
/* something got written, it can have been truncated now */
|
||||
wsi->could_have_pending = 1;
|
||||
|
||||
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,
|
||||
* ie, implying treat it was a truncated send so it gets
|
||||
* retried
|
||||
*/
|
||||
n = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* we were already handling a truncated send?
|
||||
*/
|
||||
if (wsi->trunc_len) {
|
||||
lwsl_info("%p partial adv %d (vs %ld)\n", wsi, n, (long)real_len);
|
||||
wsi->trunc_offset += n;
|
||||
wsi->trunc_len -= n;
|
||||
|
||||
if (!wsi->trunc_len) {
|
||||
lwsl_info("** %p partial send completed\n", wsi);
|
||||
/* done with it, but don't free it */
|
||||
n = (int)real_len;
|
||||
if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
|
||||
lwsl_info("** %p signalling to close now\n", wsi);
|
||||
return -1; /* retry closing now */
|
||||
}
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
#if !defined(LWS_WITHOUT_SERVER)
|
||||
if (wsi->http.deferred_transaction_completed) {
|
||||
lwsl_notice("%s: partial completed, doing "
|
||||
"deferred transaction completed\n",
|
||||
__func__);
|
||||
wsi->http.deferred_transaction_completed = 0;
|
||||
return lws_http_transaction_completed(wsi);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
/* always callback on writeable */
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
if ((unsigned int)n == real_len)
|
||||
/* what we just sent went out cleanly */
|
||||
return n;
|
||||
|
||||
/*
|
||||
* Newly truncated send. Buffer the remainder (it will get
|
||||
* first priority next time the socket is writable).
|
||||
*/
|
||||
lwsl_debug("%p new partial sent %d from %lu total\n", wsi, n,
|
||||
(unsigned long)real_len);
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITE_PARTIALS, 1);
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, n);
|
||||
|
||||
/*
|
||||
* - 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->trunc_alloc || real_len - n > wsi->trunc_alloc_len) {
|
||||
lws_free(wsi->trunc_alloc);
|
||||
|
||||
wsi->trunc_alloc_len = (unsigned int)(real_len - n);
|
||||
wsi->trunc_alloc = lws_malloc(real_len - n,
|
||||
"truncated send alloc");
|
||||
if (!wsi->trunc_alloc) {
|
||||
lwsl_err("truncated send: unable to malloc %lu\n",
|
||||
(unsigned long)(real_len - n));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
wsi->trunc_offset = 0;
|
||||
wsi->trunc_len = (unsigned int)(real_len - n);
|
||||
memcpy(wsi->trunc_alloc, buf + n, real_len - n);
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
/* stash original destination for fulfilling UDP partials */
|
||||
wsi->udp->sa_pending = wsi->udp->sa;
|
||||
wsi->udp->salen_pending = wsi->udp->salen;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* since something buffered, force it to get another chance to send */
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return (int)real_len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
||||
enum lws_write_protocol wp)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
struct lws_write_passthru pas;
|
||||
|
||||
pas.buf = buf;
|
||||
pas.len = len;
|
||||
pas.wp = wp;
|
||||
pas.wsi = wsi;
|
||||
|
||||
if (wsi->parent->protocol->callback(wsi->parent,
|
||||
LWS_CALLBACK_CHILD_WRITE_VIA_PARENT,
|
||||
wsi->parent->user_space,
|
||||
(void *)&pas, 0))
|
||||
return 1;
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_LWS_WRITE, 1);
|
||||
|
||||
if ((int)len < 0) {
|
||||
lwsl_err("%s: suspicious len int %d, ulong %lu\n", __func__,
|
||||
(int)len, (unsigned long)len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_WRITE, len);
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
wsi->http.access_log.sent += len;
|
||||
#endif
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->conn_stats.tx += len;
|
||||
|
||||
assert(wsi->role_ops);
|
||||
if (!wsi->role_ops->write_role_protocol)
|
||||
return lws_issue_raw(wsi, buf, len);
|
||||
|
||||
return wsi->role_ops->write_role_protocol(wsi, buf, len, &wp);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n = 0;
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
|
||||
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
wsi->udp->salen = sizeof(wsi->udp->sa);
|
||||
n = recvfrom(wsi->desc.sockfd, (char *)buf, len, 0,
|
||||
&wsi->udp->sa, &wsi->udp->salen);
|
||||
#endif
|
||||
} else
|
||||
n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
|
||||
|
||||
if (n >= 0) {
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->conn_stats.rx += n;
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
if (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK ||
|
||||
LWS_ERRNO == LWS_EINTR)
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
lwsl_notice("error on reading from skt : %d\n", LWS_ERRNO);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (wsi->trunc_len)
|
||||
n = sendto(wsi->desc.sockfd, buf, len, 0, &wsi->udp->sa_pending, wsi->udp->salen_pending);
|
||||
else
|
||||
n = sendto(wsi->desc.sockfd, buf, len, 0, &wsi->udp->sa, wsi->udp->salen);
|
||||
#endif
|
||||
} else
|
||||
n = send(wsi->desc.sockfd, (char *)buf, len, MSG_NOSIGNAL);
|
||||
// lwsl_info("%s: sent len %d result %d", __func__, len, n);
|
||||
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 fd %d err %d / errno %d\n",
|
||||
len, wsi->desc.sockfd, n, LWS_ERRNO);
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_pending_no_ssl(struct lws *wsi)
|
||||
{
|
||||
(void)wsi;
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
return 100;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
|
@ -1,616 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
int
|
||||
_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
|
||||
{
|
||||
#if !defined(LWS_WITH_LIBUV) && !defined(LWS_WITH_LIBEV) && !defined(LWS_WITH_LIBEVENT)
|
||||
volatile struct lws_context_per_thread *vpt;
|
||||
#endif
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_context *context;
|
||||
int ret = 0, pa_events = 1;
|
||||
struct lws_pollfd *pfd;
|
||||
int sampled_tid, tid;
|
||||
|
||||
if (!wsi)
|
||||
return 0;
|
||||
|
||||
assert(wsi->position_in_fds_table == LWS_NO_FDS_POS ||
|
||||
wsi->position_in_fds_table >= 0);
|
||||
|
||||
if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
|
||||
return 0;
|
||||
|
||||
if (((volatile struct lws *)wsi)->handling_pollout &&
|
||||
!_and && _or == LWS_POLLOUT) {
|
||||
/*
|
||||
* Happening alongside service thread handling POLLOUT.
|
||||
* The danger is when he is finished, he will disable POLLOUT,
|
||||
* countermanding what we changed here.
|
||||
*
|
||||
* Instead of changing the fds, inform the service thread
|
||||
* what happened, and ask it to leave POLLOUT active on exit
|
||||
*/
|
||||
((volatile struct lws *)wsi)->leave_pollout_active = 1;
|
||||
/*
|
||||
* by definition service thread is not in poll wait, so no need
|
||||
* to cancel service
|
||||
*/
|
||||
|
||||
lwsl_debug("%s: using leave_pollout_active\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
context = wsi->context;
|
||||
pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
assert(wsi->position_in_fds_table < (int)pt->fds_count);
|
||||
|
||||
#if !defined(LWS_WITH_LIBUV) && \
|
||||
!defined(LWS_WITH_LIBEV) && \
|
||||
!defined(LWS_WITH_LIBEVENT)
|
||||
/*
|
||||
* This only applies when we use the default poll() event loop.
|
||||
*
|
||||
* BSD can revert pa->events at any time, when the kernel decides to
|
||||
* exit from poll(). We can't protect against it using locking.
|
||||
*
|
||||
* Therefore we must check first if the service thread is in poll()
|
||||
* wait; if so, we know we must be being called from a foreign thread,
|
||||
* and we must keep a strictly ordered list of changes we made instead
|
||||
* of trying to apply them, since when poll() exits, which may happen
|
||||
* at any time it would revert our changes.
|
||||
*
|
||||
* The plat code will apply them when it leaves the poll() wait
|
||||
* before doing anything else.
|
||||
*/
|
||||
|
||||
vpt = (volatile struct lws_context_per_thread *)pt;
|
||||
|
||||
vpt->foreign_spinlock = 1;
|
||||
lws_memory_barrier();
|
||||
|
||||
if (vpt->inside_poll) {
|
||||
struct lws_foreign_thread_pollfd *ftp, **ftp1;
|
||||
/*
|
||||
* We are certainly a foreign thread trying to change events
|
||||
* while the service thread is in the poll() wait.
|
||||
*
|
||||
* Create a list of changes to be applied after poll() exit,
|
||||
* instead of trying to apply them now.
|
||||
*/
|
||||
ftp = lws_malloc(sizeof(*ftp), "ftp");
|
||||
if (!ftp) {
|
||||
vpt->foreign_spinlock = 0;
|
||||
lws_memory_barrier();
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ftp->_and = _and;
|
||||
ftp->_or = _or;
|
||||
ftp->fd_index = wsi->position_in_fds_table;
|
||||
ftp->next = NULL;
|
||||
|
||||
/* place at END of list to maintain order */
|
||||
ftp1 = (struct lws_foreign_thread_pollfd **)
|
||||
&vpt->foreign_pfd_list;
|
||||
while (*ftp1)
|
||||
ftp1 = &((*ftp1)->next);
|
||||
|
||||
*ftp1 = ftp;
|
||||
vpt->foreign_spinlock = 0;
|
||||
lws_memory_barrier();
|
||||
lws_cancel_service_pt(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpt->foreign_spinlock = 0;
|
||||
lws_memory_barrier();
|
||||
#endif
|
||||
|
||||
pfd = &pt->fds[wsi->position_in_fds_table];
|
||||
pa->fd = wsi->desc.sockfd;
|
||||
lwsl_debug("%s: wsi %p: fd %d events %d -> %d\n", __func__, wsi, pa->fd, pfd->events, (pfd->events & ~_and) | _or);
|
||||
pa->prev_events = pfd->events;
|
||||
pa->events = pfd->events = (pfd->events & ~_and) | _or;
|
||||
|
||||
if (wsi->http2_substream)
|
||||
return 0;
|
||||
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_CHANGE_MODE_POLL_FD,
|
||||
wsi->user_space, (void *)pa, 0)) {
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (context->event_loop_ops->io) {
|
||||
if (_and & LWS_POLLIN)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_READ);
|
||||
|
||||
if (_or & LWS_POLLIN)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
if (_and & LWS_POLLOUT)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_WRITE);
|
||||
|
||||
if (_or & LWS_POLLOUT)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_START | LWS_EV_WRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
pa_events = pa->prev_events != pa->events;
|
||||
|
||||
if (pa_events) {
|
||||
if (lws_plat_change_pollfd(context, wsi, pfd)) {
|
||||
lwsl_info("%s failed\n", __func__);
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
sampled_tid = context->service_tid;
|
||||
if (sampled_tid && wsi->vhost) {
|
||||
tid = wsi->vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
if (tid == -1) {
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
if (tid != sampled_tid)
|
||||
lws_cancel_service_pt(wsi);
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
/*
|
||||
* Enable or disable listen sockets on this pt globally...
|
||||
* it's modulated according to the pt having space for a new accept.
|
||||
*/
|
||||
static void
|
||||
lws_accept_modulation(struct lws_context *context,
|
||||
struct lws_context_per_thread *pt, int allow)
|
||||
{
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
struct lws_pollargs pa1;
|
||||
|
||||
while (vh) {
|
||||
if (vh->lserv_wsi) {
|
||||
if (allow)
|
||||
_lws_change_pollfd(vh->lserv_wsi,
|
||||
0, LWS_POLLIN, &pa1);
|
||||
else
|
||||
_lws_change_pollfd(vh->lserv_wsi,
|
||||
LWS_POLLIN, 0, &pa1);
|
||||
}
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
__insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_pollargs pa = { wsi->desc.sockfd, LWS_POLLIN, 0 };
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int ret = 0;
|
||||
|
||||
|
||||
lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n",
|
||||
__func__, wsi, wsi->tsi, wsi->desc.sockfd, pt->fds_count);
|
||||
|
||||
if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) {
|
||||
lwsl_err("Too many fds (%d vs %d)\n", context->max_fds,
|
||||
context->fd_limit_per_thread );
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
if (wsi->desc.sockfd - lws_plat_socket_offset() >= context->max_fds) {
|
||||
lwsl_err("Socket fd %d is too high (%d) offset %d\n",
|
||||
wsi->desc.sockfd, context->max_fds, lws_plat_socket_offset());
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(wsi);
|
||||
assert(wsi->event_pipe || wsi->vhost);
|
||||
assert(lws_socket_is_valid(wsi->desc.sockfd));
|
||||
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 1))
|
||||
return -1;
|
||||
|
||||
pt->count_conns++;
|
||||
insert_wsi(context, wsi);
|
||||
wsi->position_in_fds_table = pt->fds_count;
|
||||
|
||||
pt->fds[wsi->position_in_fds_table].fd = wsi->desc.sockfd;
|
||||
pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN;
|
||||
pa.events = pt->fds[pt->fds_count].events;
|
||||
|
||||
lws_plat_insert_socket_into_fds(context, wsi);
|
||||
|
||||
/* external POLL support via protocol 0 */
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
ret = -1;
|
||||
#ifndef LWS_NO_SERVER
|
||||
/* if no more room, defeat accepts on this thread */
|
||||
if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1)
|
||||
lws_accept_modulation(context, pt, 0);
|
||||
#endif
|
||||
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *)&pa, 1))
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
__remove_wsi_socket_from_fds(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_pollargs pa = { wsi->desc.sockfd, 0, 0 };
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws *end_wsi;
|
||||
int v;
|
||||
int m, ret = 0;
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
lws_same_vh_protocol_remove(wsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
if (wsi->desc.sockfd - lws_plat_socket_offset() > context->max_fds) {
|
||||
lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd,
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *)&pa, 1))
|
||||
return -1;
|
||||
|
||||
lws_same_vh_protocol_remove(wsi);
|
||||
|
||||
/* the guy who is to be deleted's slot index in pt->fds */
|
||||
m = wsi->position_in_fds_table;
|
||||
|
||||
/* these are the only valid possibilities for position_in_fds_table */
|
||||
assert(m == LWS_NO_FDS_POS || (m >= 0 &&
|
||||
(unsigned int)m < pt->fds_count));
|
||||
|
||||
if (context->event_loop_ops->io)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
|
||||
LWS_EV_PREPARE_DELETION);
|
||||
|
||||
lwsl_debug("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
|
||||
__func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,
|
||||
pt->fds_count, pt->fds[pt->fds_count].fd);
|
||||
|
||||
if (m != LWS_NO_FDS_POS) {
|
||||
|
||||
/* have the last guy take up the now vacant slot */
|
||||
pt->fds[m] = pt->fds[pt->fds_count - 1];
|
||||
/* this decrements pt->fds_count */
|
||||
lws_plat_delete_socket_from_fds(context, wsi, m);
|
||||
v = (int) pt->fds[m].fd;
|
||||
/* end guy's "position in fds table" is now the deletion guy's old one */
|
||||
end_wsi = wsi_from_fd(context, v);
|
||||
if (!end_wsi) {
|
||||
lwsl_err("no wsi for fd %d at pos %d, pt->fds_count=%d\n",
|
||||
(int)pt->fds[m].fd, m, pt->fds_count);
|
||||
assert(0);
|
||||
} else
|
||||
end_wsi->position_in_fds_table = m;
|
||||
|
||||
/* deletion guy's lws_lookup entry needs nuking */
|
||||
delete_from_fd(context, wsi->desc.sockfd);
|
||||
|
||||
/* removed wsi has no position any more */
|
||||
wsi->position_in_fds_table = LWS_NO_FDS_POS;
|
||||
}
|
||||
|
||||
/* remove also from external POLL support via protocol 0 */
|
||||
if (lws_socket_is_valid(wsi->desc.sockfd) && wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
ret = -1;
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
if (!context->being_destroyed &&
|
||||
/* if this made some room, accept connects on this thread */
|
||||
(unsigned int)pt->fds_count < context->fd_limit_per_thread - 1)
|
||||
lws_accept_modulation(context, pt, 1);
|
||||
#endif
|
||||
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 1))
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
__lws_change_pollfd(struct lws *wsi, int _and, int _or)
|
||||
{
|
||||
struct lws_context *context;
|
||||
struct lws_pollargs pa;
|
||||
int ret = 0;
|
||||
|
||||
if (!wsi || (!wsi->protocol && !wsi->event_pipe) ||
|
||||
wsi->position_in_fds_table == LWS_NO_FDS_POS)
|
||||
return 0;
|
||||
|
||||
context = lws_get_context(wsi);
|
||||
if (!context)
|
||||
return 1;
|
||||
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
return -1;
|
||||
|
||||
ret = _lws_change_pollfd(wsi, _and, _or, &pa);
|
||||
if (wsi->vhost &&
|
||||
wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lws_change_pollfd(struct lws *wsi, int _and, int _or)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int ret = 0;
|
||||
|
||||
pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
ret = __lws_change_pollfd(wsi, _and, _or);
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n;
|
||||
|
||||
if (lwsi_state(wsi) == LRS_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
if (wsi->socket_is_permanently_unusable)
|
||||
return 0;
|
||||
|
||||
pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->active_writable_req_us) {
|
||||
wsi->active_writable_req_us = time_in_microseconds();
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_WRITEABLE_CB_EFF_REQ, 1);
|
||||
}
|
||||
#endif
|
||||
n = lws_callback_on_writable(wsi->parent);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
wsi->parent_pending_cb_on_writable = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->active_writable_req_us) {
|
||||
wsi->active_writable_req_us = time_in_microseconds();
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_WRITEABLE_CB_EFF_REQ, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (wsi->role_ops->callback_on_writable) {
|
||||
if (wsi->role_ops->callback_on_writable(wsi))
|
||||
return 1;
|
||||
wsi = lws_get_network_wsi(wsi);
|
||||
}
|
||||
|
||||
if (wsi->position_in_fds_table == LWS_NO_FDS_POS) {
|
||||
lwsl_debug("%s: failed to find socket %d\n", __func__,
|
||||
wsi->desc.sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__lws_change_pollfd(wsi, 0, LWS_POLLOUT))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* stitch protocol choice into the vh protocol linked list
|
||||
* We always insert ourselves at the start of the list
|
||||
*
|
||||
* X <-> B
|
||||
* X <-> pAn <-> pB
|
||||
*
|
||||
* Illegal to attach more than once without detach inbetween
|
||||
*/
|
||||
void
|
||||
lws_same_vh_protocol_insert(struct lws *wsi, int n)
|
||||
{
|
||||
if (wsi->same_vh_protocol_prev || wsi->same_vh_protocol_next) {
|
||||
lws_same_vh_protocol_remove(wsi);
|
||||
lwsl_notice("Attempted to attach wsi twice to same vh prot\n");
|
||||
}
|
||||
|
||||
lws_vhost_lock(wsi->vhost);
|
||||
|
||||
wsi->same_vh_protocol_prev = &wsi->vhost->same_vh_protocol_list[n];
|
||||
/* old first guy is our next */
|
||||
wsi->same_vh_protocol_next = wsi->vhost->same_vh_protocol_list[n];
|
||||
/* we become the new first guy */
|
||||
wsi->vhost->same_vh_protocol_list[n] = wsi;
|
||||
|
||||
if (wsi->same_vh_protocol_next)
|
||||
/* old first guy points back to us now */
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
&wsi->same_vh_protocol_next;
|
||||
|
||||
wsi->on_same_vh_list = 1;
|
||||
|
||||
lws_vhost_unlock(wsi->vhost);
|
||||
}
|
||||
|
||||
void
|
||||
lws_same_vh_protocol_remove(struct lws *wsi)
|
||||
{
|
||||
/*
|
||||
* detach ourselves from vh protocol list if we're on one
|
||||
* A -> B -> C
|
||||
* A -> C , or, B -> C, or A -> B
|
||||
*
|
||||
* OK to call on already-detached wsi
|
||||
*/
|
||||
lwsl_info("%s: removing same prot wsi %p\n", __func__, wsi);
|
||||
|
||||
if (!wsi->vhost || !wsi->on_same_vh_list)
|
||||
return;
|
||||
|
||||
lws_vhost_lock(wsi->vhost);
|
||||
|
||||
if (wsi->same_vh_protocol_prev) {
|
||||
assert (*(wsi->same_vh_protocol_prev) == wsi);
|
||||
lwsl_info("have prev %p, setting him to our next %p\n",
|
||||
wsi->same_vh_protocol_prev,
|
||||
wsi->same_vh_protocol_next);
|
||||
|
||||
/* guy who pointed to us should point to our next */
|
||||
*(wsi->same_vh_protocol_prev) = wsi->same_vh_protocol_next;
|
||||
}
|
||||
|
||||
/* our next should point back to our prev */
|
||||
if (wsi->same_vh_protocol_next)
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
wsi->same_vh_protocol_prev;
|
||||
|
||||
wsi->same_vh_protocol_prev = NULL;
|
||||
wsi->same_vh_protocol_next = NULL;
|
||||
wsi->on_same_vh_list = 0;
|
||||
|
||||
lws_vhost_unlock(wsi->vhost);
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
|
||||
const struct lws_protocols *protocol)
|
||||
{
|
||||
struct lws *wsi;
|
||||
|
||||
if (protocol < vhost->protocols ||
|
||||
protocol >= (vhost->protocols + vhost->count_protocols)) {
|
||||
lwsl_err("%s: protocol %p is not from vhost %p (%p - %p)\n",
|
||||
__func__, protocol, vhost->protocols, vhost,
|
||||
(vhost->protocols + vhost->count_protocols));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsi = vhost->same_vh_protocol_list[protocol - vhost->protocols];
|
||||
while (wsi) {
|
||||
assert(wsi->protocol == protocol);
|
||||
assert(*wsi->same_vh_protocol_prev == wsi);
|
||||
if (wsi->same_vh_protocol_next)
|
||||
assert(wsi->same_vh_protocol_next->
|
||||
same_vh_protocol_prev ==
|
||||
&wsi->same_vh_protocol_next);
|
||||
|
||||
lws_callback_on_writable(wsi);
|
||||
wsi = wsi->same_vh_protocol_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol(const struct lws_context *context,
|
||||
const struct lws_protocols *protocol)
|
||||
{
|
||||
struct lws_vhost *vhost;
|
||||
int n;
|
||||
|
||||
if (!context)
|
||||
return 0;
|
||||
|
||||
vhost = context->vhost_list;
|
||||
|
||||
while (vhost) {
|
||||
for (n = 0; n < vhost->count_protocols; n++)
|
||||
if (protocol->callback ==
|
||||
vhost->protocols[n].callback &&
|
||||
!strcmp(protocol->name, vhost->protocols[n].name))
|
||||
break;
|
||||
if (n != vhost->count_protocols)
|
||||
lws_callback_on_writable_all_protocol_vhost(
|
||||
vhost, &vhost->protocols[n]);
|
||||
|
||||
vhost = vhost->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,987 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 "core/private.h"
|
||||
|
||||
int
|
||||
lws_callback_as_writeable(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int n, m;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (wsi->active_writable_req_us) {
|
||||
uint64_t ul = time_in_microseconds() -
|
||||
wsi->active_writable_req_us;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_MS_WRITABLE_DELAY, ul);
|
||||
lws_stats_atomic_max(wsi->context, pt,
|
||||
LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
|
||||
wsi->active_writable_req_us = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
n = wsi->role_ops->writeable_cb[lwsi_role_server(wsi)];
|
||||
|
||||
m = user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, (enum lws_callback_reasons) n,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
||||
{
|
||||
volatile struct lws *vwsi = (volatile struct lws *)wsi;
|
||||
int n;
|
||||
|
||||
//lwsl_notice("%s: %p\n", __func__, wsi);
|
||||
|
||||
vwsi->leave_pollout_active = 0;
|
||||
vwsi->handling_pollout = 1;
|
||||
/*
|
||||
* if another thread wants POLLOUT on us, from here on while
|
||||
* handling_pollout is set, he will only set leave_pollout_active.
|
||||
* If we are going to disable POLLOUT, we will check that first.
|
||||
*/
|
||||
wsi->could_have_pending = 0; /* clear back-to-back write detection */
|
||||
|
||||
/*
|
||||
* user callback is lowest priority to get these notifications
|
||||
* actually, since other pending things cannot be disordered
|
||||
*
|
||||
* Priority 1: pending truncated sends are incomplete ws fragments
|
||||
* If anything else sent first the protocol would be
|
||||
* corrupted.
|
||||
*/
|
||||
|
||||
if (wsi->trunc_len) {
|
||||
//lwsl_notice("%s: completing partial\n", __func__);
|
||||
if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset,
|
||||
wsi->trunc_len) < 0) {
|
||||
lwsl_info("%s signalling to close\n", __func__);
|
||||
goto bail_die;
|
||||
}
|
||||
/* leave POLLOUT active either way */
|
||||
goto bail_ok;
|
||||
} else
|
||||
if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
goto bail_die; /* retry closing now */
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/*
|
||||
* A cgi master's wire protocol remains h1 or h2. He is just getting
|
||||
* his data from his child cgis.
|
||||
*/
|
||||
if (wsi->http.cgi) {
|
||||
/* also one shot */
|
||||
if (pollfd)
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
return 1;
|
||||
}
|
||||
goto user_service_go_again;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if we got here, we should have wire protocol ops set on the wsi */
|
||||
assert(wsi->role_ops);
|
||||
|
||||
if (!wsi->role_ops->handle_POLLOUT)
|
||||
goto bail_ok;
|
||||
|
||||
switch ((wsi->role_ops->handle_POLLOUT)(wsi)) {
|
||||
case LWS_HP_RET_BAIL_OK:
|
||||
goto bail_ok;
|
||||
case LWS_HP_RET_BAIL_DIE:
|
||||
goto bail_die;
|
||||
case LWS_HP_RET_USER_SERVICE:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* one shot */
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
vwsi->handling_pollout = 0;
|
||||
vwsi->leave_pollout_active = 0;
|
||||
|
||||
return lws_callback_as_writeable(wsi);
|
||||
}
|
||||
|
||||
if (pollfd) {
|
||||
int eff = vwsi->leave_pollout_active;
|
||||
|
||||
if (!eff) {
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
goto bail_die;
|
||||
}
|
||||
}
|
||||
|
||||
vwsi->handling_pollout = 0;
|
||||
|
||||
/* cannot get leave_pollout_active set after the above */
|
||||
if (!eff && wsi->leave_pollout_active) {
|
||||
/*
|
||||
* got set inbetween sampling eff and clearing
|
||||
* handling_pollout, force POLLOUT on
|
||||
*/
|
||||
lwsl_debug("leave_pollout_active\n");
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
goto bail_die;
|
||||
}
|
||||
}
|
||||
|
||||
vwsi->leave_pollout_active = 0;
|
||||
}
|
||||
|
||||
if (lwsi_role_client(wsi) &&
|
||||
!wsi->hdr_parsing_completed &&
|
||||
lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS &&
|
||||
lwsi_state(wsi) != LRS_ISSUE_HTTP_BODY
|
||||
)
|
||||
goto bail_ok;
|
||||
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
user_service_go_again:
|
||||
#endif
|
||||
|
||||
if (wsi->role_ops->perform_user_POLLOUT) {
|
||||
if (wsi->role_ops->perform_user_POLLOUT(wsi) == -1)
|
||||
goto bail_die;
|
||||
else
|
||||
goto bail_ok;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: %p: non mux: wsistate 0x%x, ops %s\n", __func__, wsi,
|
||||
wsi->wsistate, wsi->role_ops->name);
|
||||
|
||||
vwsi = (volatile struct lws *)wsi;
|
||||
vwsi->leave_pollout_active = 0;
|
||||
|
||||
n = lws_callback_as_writeable(wsi);
|
||||
vwsi->handling_pollout = 0;
|
||||
|
||||
if (vwsi->leave_pollout_active)
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLOUT);
|
||||
|
||||
return n;
|
||||
|
||||
/*
|
||||
* since these don't disable the POLLOUT, they are always doing the
|
||||
* right thing for leave_pollout_active whether it was set or not.
|
||||
*/
|
||||
|
||||
bail_ok:
|
||||
vwsi->handling_pollout = 0;
|
||||
vwsi->leave_pollout_active = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
bail_die:
|
||||
vwsi->handling_pollout = 0;
|
||||
vwsi->leave_pollout_active = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
__lws_service_timeout_check(struct lws *wsi, time_t sec)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int n = 0;
|
||||
|
||||
(void)n;
|
||||
|
||||
/*
|
||||
* if we went beyond the allowed time, kill the
|
||||
* connection
|
||||
*/
|
||||
if (wsi->dll_timeout.prev &&
|
||||
lws_compare_time_t(wsi->context, sec, wsi->pending_timeout_set) >
|
||||
wsi->pending_timeout_limit) {
|
||||
|
||||
if (wsi->desc.sockfd != LWS_SOCK_INVALID &&
|
||||
wsi->position_in_fds_table >= 0)
|
||||
n = pt->fds[wsi->position_in_fds_table].events;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_TIMEOUTS, 1);
|
||||
|
||||
/* no need to log normal idle keepalive timeout */
|
||||
if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE)
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
lwsl_info("wsi %p: TIMEDOUT WAITING on %d "
|
||||
"(did hdr %d, ah %p, wl %d, pfd "
|
||||
"events %d) %llu vs %llu\n",
|
||||
(void *)wsi, wsi->pending_timeout,
|
||||
wsi->hdr_parsing_completed, wsi->http.ah,
|
||||
pt->http.ah_wait_list_length, n,
|
||||
(unsigned long long)sec,
|
||||
(unsigned long long)wsi->pending_timeout_limit);
|
||||
#if defined(LWS_WITH_CGI)
|
||||
if (wsi->http.cgi)
|
||||
lwsl_notice("CGI timeout: %s\n", wsi->http.cgi->summary);
|
||||
#endif
|
||||
#else
|
||||
lwsl_info("wsi %p: TIMEDOUT WAITING on %d ", (void *)wsi,
|
||||
wsi->pending_timeout);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since he failed a timeout, he already had a chance to do
|
||||
* something and was unable to... that includes situations like
|
||||
* half closed connections. So process this "failed timeout"
|
||||
* close as a violent death and don't try to do protocol
|
||||
* cleanup like flush partials.
|
||||
*/
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
if (lwsi_state(wsi) == LRS_WAITING_SSL && wsi->protocol)
|
||||
wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
|
||||
wsi->user_space,
|
||||
(void *)"Timed out waiting SSL", 21);
|
||||
|
||||
__lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "timeout");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
uint8_t *buffered;
|
||||
size_t blen;
|
||||
int ret = 0, m;
|
||||
|
||||
/* his RX is flowcontrolled, don't send remaining now */
|
||||
blen = lws_buflist_next_segment_len(&wsi->buflist, &buffered);
|
||||
if (blen) {
|
||||
if (buf >= buffered && buf + len <= buffered + blen) {
|
||||
/* rxflow while we were spilling prev rxflow */
|
||||
lwsl_info("%s: staying in rxflow buf\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/* a new rxflow, buffer it and warn caller */
|
||||
|
||||
m = lws_buflist_append_segment(&wsi->buflist, buf + n, len - n);
|
||||
|
||||
if (m < 0)
|
||||
return -1;
|
||||
if (m) {
|
||||
lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
|
||||
lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this is used by the platform service code to stop us waiting for network
|
||||
* activity in poll() when we have something that already needs service
|
||||
*/
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
|
||||
/* Figure out if we really want to wait in poll()
|
||||
* We only need to wait if really nothing already to do and we have
|
||||
* to wait for something from network
|
||||
*/
|
||||
#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
/* 1) if we know we are draining rx ext, do not wait in poll */
|
||||
if (pt->ws.rx_draining_ext_list)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* 2) if we know we have non-network pending data, do not wait in poll */
|
||||
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
if (pt->context->tls_ops->fake_POLLIN_for_buffered(pt))
|
||||
return 0;
|
||||
|
||||
/* 3) If there is any wsi with rxflow buffered and in a state to process
|
||||
* it, we should not wait in poll
|
||||
*/
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll_lws *, d, pt->dll_head_buflist.next) {
|
||||
struct lws *wsi = lws_container_of(d, struct lws, dll_buflist);
|
||||
|
||||
if (lwsi_state(wsi) != LRS_DEFERRING_ACTION)
|
||||
return 0;
|
||||
|
||||
} lws_end_foreach_dll(d);
|
||||
|
||||
return timeout_ms;
|
||||
}
|
||||
|
||||
/*
|
||||
* POLLIN said there is something... we must read it, and either use it; or
|
||||
* if other material already in the buflist append it and return the buflist
|
||||
* head material.
|
||||
*/
|
||||
int
|
||||
lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_tokens *ebuf)
|
||||
{
|
||||
int n, prior = (int)lws_buflist_next_segment_len(&wsi->buflist, NULL);
|
||||
|
||||
ebuf->token = (char *)pt->serv_buf;
|
||||
ebuf->len = lws_ssl_capable_read(wsi, pt->serv_buf,
|
||||
wsi->context->pt_serv_buf_size);
|
||||
|
||||
if (ebuf->len == LWS_SSL_CAPABLE_MORE_SERVICE && prior)
|
||||
goto get_from_buflist;
|
||||
|
||||
if (ebuf->len <= 0)
|
||||
return 0;
|
||||
|
||||
/* nothing in buflist already? Then just use what we read */
|
||||
|
||||
if (!prior)
|
||||
return 0;
|
||||
|
||||
/* stash what we read */
|
||||
|
||||
n = lws_buflist_append_segment(&wsi->buflist, (uint8_t *)ebuf->token,
|
||||
ebuf->len);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n) {
|
||||
lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
|
||||
lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
|
||||
}
|
||||
|
||||
/* get the first buflist guy in line */
|
||||
|
||||
get_from_buflist:
|
||||
|
||||
ebuf->len = (int)lws_buflist_next_segment_len(&wsi->buflist,
|
||||
(uint8_t **)&ebuf->token);
|
||||
|
||||
return 1; /* came from buflist */
|
||||
}
|
||||
|
||||
int
|
||||
lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
|
||||
int buffered)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int m;
|
||||
|
||||
/* it's in the buflist; we didn't use any */
|
||||
|
||||
if (!used && buffered)
|
||||
return 0;
|
||||
|
||||
if (used && buffered) {
|
||||
m = lws_buflist_use_segment(&wsi->buflist, used);
|
||||
lwsl_info("%s: draining rxflow: used %d, next %d\n",
|
||||
__func__, used, m);
|
||||
if (m)
|
||||
return 0;
|
||||
|
||||
lwsl_info("%s: removed %p from dll_buflist\n", __func__, wsi);
|
||||
lws_dll_lws_remove(&wsi->dll_buflist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* any remainder goes on the buflist */
|
||||
|
||||
if (used != ebuf->len) {
|
||||
m = lws_buflist_append_segment(&wsi->buflist,
|
||||
(uint8_t *)ebuf->token + used,
|
||||
ebuf->len - used);
|
||||
if (m < 0)
|
||||
return 1; /* OOM */
|
||||
if (m) {
|
||||
lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
|
||||
lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt)
|
||||
{
|
||||
struct lws_pollfd pfd;
|
||||
|
||||
if (!pt->dll_head_buflist.next)
|
||||
return;
|
||||
|
||||
/*
|
||||
* service all guys with pending rxflow that reached a state they can
|
||||
* accept the pending data
|
||||
*/
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
|
||||
pt->dll_head_buflist.next) {
|
||||
struct lws *wsi = lws_container_of(d, struct lws, dll_buflist);
|
||||
|
||||
pfd.events = LWS_POLLIN;
|
||||
pfd.revents = LWS_POLLIN;
|
||||
pfd.fd = -1;
|
||||
|
||||
lwsl_debug("%s: rxflow processing: %p 0x%x\n", __func__, wsi,
|
||||
wsi->wsistate);
|
||||
|
||||
if (!lws_is_flowcontrolled(wsi) &&
|
||||
lwsi_state(wsi) != LRS_DEFERRING_ACTION &&
|
||||
(wsi->role_ops->handle_POLLIN)(pt, wsi, &pfd) ==
|
||||
LWS_HPI_RET_PLEASE_CLOSE_ME)
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"close_and_handled");
|
||||
|
||||
} lws_end_foreach_dll_safe(d, d1);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
/*
|
||||
* guys that need POLLIN service again without waiting for network action
|
||||
* can force POLLIN here if not flowcontrolled, so they will get service.
|
||||
*
|
||||
* Return nonzero if anybody got their POLLIN faked
|
||||
*/
|
||||
int
|
||||
lws_service_flag_pending(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
struct lws *wsi, *wsi_next;
|
||||
#endif
|
||||
int forced = 0;
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
/*
|
||||
* 1) If there is any wsi with a buflist and in a state to process
|
||||
* it, we should not wait in poll
|
||||
*/
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll_lws *, d, pt->dll_head_buflist.next) {
|
||||
struct lws *wsi = lws_container_of(d, struct lws, dll_buflist);
|
||||
|
||||
if (lwsi_state(wsi) != LRS_DEFERRING_ACTION) {
|
||||
forced = 1;
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_dll(d);
|
||||
|
||||
#if defined(LWS_ROLE_WS)
|
||||
forced |= role_ops_ws.service_flag_pending(context, tsi);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
/*
|
||||
* 2) For all guys with buffered SSL read data already saved up, if they
|
||||
* are not flowcontrolled, fake their POLLIN status so they'll get
|
||||
* service to use up the buffered incoming data, even though their
|
||||
* network socket may have nothing
|
||||
*/
|
||||
wsi = pt->tls.pending_read_list;
|
||||
while (wsi) {
|
||||
wsi_next = wsi->tls.pending_read_list_next;
|
||||
pt->fds[wsi->position_in_fds_table].revents |=
|
||||
pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
|
||||
if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN) {
|
||||
forced = 1;
|
||||
/*
|
||||
* he's going to get serviced now, take him off the
|
||||
* list of guys with buffered SSL. If he still has some
|
||||
* at the end of the service, he'll get put back on the
|
||||
* list then.
|
||||
*/
|
||||
__lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
}
|
||||
|
||||
wsi = wsi_next;
|
||||
}
|
||||
#endif
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
return forced;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_service_periodic_checks(struct lws_context *context,
|
||||
struct lws_pollfd *pollfd, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
lws_sockfd_type our_fd = 0, tmp_fd;
|
||||
struct lws *wsi;
|
||||
int timed_out = 0;
|
||||
time_t now;
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
struct allocated_headers *ah;
|
||||
int m;
|
||||
#endif
|
||||
|
||||
if (!context->protocol_init_done)
|
||||
if (lws_protocol_init(context))
|
||||
return -1;
|
||||
|
||||
time(&now);
|
||||
|
||||
/*
|
||||
* handle case that system time was uninitialized when lws started
|
||||
* at boot, and got initialized a little later
|
||||
*/
|
||||
if (context->time_up < 1464083026 && now > 1464083026)
|
||||
context->time_up = now;
|
||||
|
||||
if (context->last_timeout_check_s &&
|
||||
now - context->last_timeout_check_s > 100) {
|
||||
/*
|
||||
* There has been a discontiguity. Any stored time that is
|
||||
* less than context->time_discontiguity should have context->
|
||||
* time_fixup added to it.
|
||||
*
|
||||
* Some platforms with no RTC will experience this as a normal
|
||||
* event when ntp sets their clock, but we can have started
|
||||
* long before that with a 0-based unix time.
|
||||
*/
|
||||
|
||||
context->time_discontiguity = now;
|
||||
context->time_fixup = now - context->last_timeout_check_s;
|
||||
|
||||
lwsl_notice("time discontiguity: at old time %llus, "
|
||||
"new time %llus: +%llus\n",
|
||||
(unsigned long long)context->last_timeout_check_s,
|
||||
(unsigned long long)context->time_discontiguity,
|
||||
(unsigned long long)context->time_fixup);
|
||||
|
||||
context->last_timeout_check_s = now - 1;
|
||||
}
|
||||
|
||||
if (!lws_compare_time_t(context, context->last_timeout_check_s, now))
|
||||
return 0;
|
||||
|
||||
context->last_timeout_check_s = now;
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!tsi && now - context->last_dump > 10) {
|
||||
lws_stats_log_dump(context);
|
||||
context->last_dump = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
lws_plat_service_periodic(context);
|
||||
lws_check_deferred_free(context, 0);
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
lws_peer_cull_peer_wait_list(context);
|
||||
#endif
|
||||
|
||||
/* retire unused deprecated context */
|
||||
#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_ESP32)
|
||||
#if !defined(_WIN32)
|
||||
if (context->deprecated && !context->count_wsi_allocated) {
|
||||
lwsl_notice("%s: ending deprecated context\n", __func__);
|
||||
kill(getpid(), SIGINT);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* global timeout check once per second */
|
||||
|
||||
if (pollfd)
|
||||
our_fd = pollfd->fd;
|
||||
|
||||
/*
|
||||
* Phase 1: check every wsi on the timeout check list
|
||||
*/
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
|
||||
context->pt[tsi].dll_head_timeout.next) {
|
||||
wsi = lws_container_of(d, struct lws, dll_timeout);
|
||||
tmp_fd = wsi->desc.sockfd;
|
||||
if (__lws_service_timeout_check(wsi, now)) {
|
||||
/* he did time out... */
|
||||
if (tmp_fd == our_fd)
|
||||
/* it was the guy we came to service! */
|
||||
timed_out = 1;
|
||||
/* he's gone, no need to mark as handled */
|
||||
}
|
||||
} lws_end_foreach_dll_safe(d, d1);
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
/*
|
||||
* Phase 2: double-check active ah timeouts independent of wsi
|
||||
* timeout status
|
||||
*/
|
||||
|
||||
ah = pt->http.ah_list;
|
||||
while (ah) {
|
||||
int len;
|
||||
char buf[256];
|
||||
const unsigned char *c;
|
||||
|
||||
if (!ah->in_use || !ah->wsi || !ah->assigned ||
|
||||
(ah->wsi->vhost &&
|
||||
lws_compare_time_t(context, now, ah->assigned) <
|
||||
ah->wsi->vhost->timeout_secs_ah_idle + 360)) {
|
||||
ah = ah->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* a single ah session somehow got held for
|
||||
* an unreasonable amount of time.
|
||||
*
|
||||
* Dump info on the connection...
|
||||
*/
|
||||
wsi = ah->wsi;
|
||||
buf[0] = '\0';
|
||||
#if !defined(LWS_PLAT_OPTEE)
|
||||
lws_get_peer_simple(wsi, buf, sizeof(buf));
|
||||
#else
|
||||
buf[0] = '\0';
|
||||
#endif
|
||||
lwsl_notice("ah excessive hold: wsi %p\n"
|
||||
" peer address: %s\n"
|
||||
" ah pos %u\n",
|
||||
wsi, buf, ah->pos);
|
||||
buf[0] = '\0';
|
||||
m = 0;
|
||||
do {
|
||||
c = lws_token_to_string(m);
|
||||
if (!c)
|
||||
break;
|
||||
if (!(*c))
|
||||
break;
|
||||
|
||||
len = lws_hdr_total_length(wsi, m);
|
||||
if (!len || len > (int)sizeof(buf) - 1) {
|
||||
m++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lws_hdr_copy(wsi, buf,
|
||||
sizeof buf, m) > 0) {
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
lwsl_notice(" %s = %s\n",
|
||||
(const char *)c, buf);
|
||||
}
|
||||
m++;
|
||||
} while (1);
|
||||
|
||||
/* explicitly detach the ah */
|
||||
lws_header_table_detach(wsi, 0);
|
||||
|
||||
/* ... and then drop the connection */
|
||||
|
||||
m = 0;
|
||||
if (wsi->desc.sockfd == our_fd) {
|
||||
m = timed_out;
|
||||
|
||||
/* it was the guy we came to service! */
|
||||
timed_out = 1;
|
||||
}
|
||||
|
||||
if (!m) /* if he didn't already timeout */
|
||||
__lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"excessive ah");
|
||||
|
||||
ah = pt->http.ah_list;
|
||||
}
|
||||
#endif
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
#if 0
|
||||
{
|
||||
char s[300], *p = s;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
p += sprintf(p, " %7lu (%5d), ",
|
||||
context->pt[n].count_conns,
|
||||
context->pt[n].fds_count);
|
||||
|
||||
lwsl_notice("load: %s\n", s);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Phase 3: vhost / protocol timer callbacks
|
||||
*/
|
||||
|
||||
wsi = NULL;
|
||||
lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
|
||||
struct lws_timed_vh_protocol *nx;
|
||||
if (v->timed_vh_protocol_list) {
|
||||
lws_start_foreach_ll(struct lws_timed_vh_protocol *,
|
||||
q, v->timed_vh_protocol_list) {
|
||||
if (now >= q->time) {
|
||||
if (!wsi)
|
||||
wsi = lws_zalloc(sizeof(*wsi), "cbwsi");
|
||||
wsi->context = context;
|
||||
wsi->vhost = v;
|
||||
wsi->protocol = q->protocol;
|
||||
lwsl_debug("timed cb: vh %s, protocol %s, reason %d\n", v->name, q->protocol->name, q->reason);
|
||||
q->protocol->callback(wsi, q->reason, NULL, NULL, 0);
|
||||
nx = q->next;
|
||||
lws_timed_callback_remove(v, q);
|
||||
q = nx;
|
||||
continue; /* we pointed ourselves to the next from the now-deleted guy */
|
||||
}
|
||||
} lws_end_foreach_ll(q, next);
|
||||
}
|
||||
} lws_end_foreach_ll(v, vhost_next);
|
||||
if (wsi)
|
||||
lws_free(wsi);
|
||||
|
||||
/*
|
||||
* Phase 4: check for unconfigured vhosts due to required
|
||||
* interface missing before
|
||||
*/
|
||||
|
||||
lws_context_lock(context);
|
||||
lws_start_foreach_llp(struct lws_vhost **, pv,
|
||||
context->no_listener_vhost_list) {
|
||||
struct lws_vhost *v = *pv;
|
||||
lwsl_debug("deferred iface: checking if on vh %s\n", (*pv)->name);
|
||||
if (_lws_vhost_init_server(NULL, *pv) == 0) {
|
||||
/* became happy */
|
||||
lwsl_notice("vh %s: became connected\n", v->name);
|
||||
*pv = v->no_listener_vhost_list;
|
||||
v->no_listener_vhost_list = NULL;
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_llp(pv, no_listener_vhost_list);
|
||||
lws_context_unlock(context);
|
||||
|
||||
/*
|
||||
* Phase 5: role periodic checks
|
||||
*/
|
||||
#if defined(LWS_ROLE_WS)
|
||||
role_ops_ws.periodic_checks(context, tsi, now);
|
||||
#endif
|
||||
#if defined(LWS_ROLE_CGI)
|
||||
role_ops_cgi.periodic_checks(context, tsi, now);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Phase 6: check the remaining cert lifetime daily
|
||||
*/
|
||||
|
||||
if (context->tls_ops &&
|
||||
context->tls_ops->periodic_housekeeping)
|
||||
context->tls_ops->periodic_housekeeping(context, now);
|
||||
|
||||
return timed_out;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
|
||||
int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws *wsi;
|
||||
|
||||
if (!context || context->being_destroyed1)
|
||||
return -1;
|
||||
|
||||
/* the socket we came to service timed out, nothing to do */
|
||||
if (lws_service_periodic_checks(context, pollfd, tsi) || !pollfd)
|
||||
return 0;
|
||||
|
||||
/* no, here to service a socket descriptor */
|
||||
wsi = wsi_from_fd(context, pollfd->fd);
|
||||
if (!wsi)
|
||||
/* 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
|
||||
*/
|
||||
|
||||
/* handle session socket closed */
|
||||
|
||||
if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
|
||||
(pollfd->revents & LWS_POLLHUP)) {
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
lwsl_debug("Session Socket %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (pollfd->revents & LWS_POLLOUT)
|
||||
wsi->sock_send_blocking = FALSE;
|
||||
#endif
|
||||
|
||||
if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
|
||||
(pollfd->revents & LWS_POLLHUP)) {
|
||||
lwsl_debug("pollhup\n");
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (lwsi_state(wsi) == LRS_SHUTDOWN &&
|
||||
lws_is_ssl(wsi) && wsi->tls.ssl) {
|
||||
switch (__lws_tls_shutdown(wsi)) {
|
||||
case LWS_SSL_CAPABLE_DONE:
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto close_and_handled;
|
||||
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
goto handled;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
wsi->could_have_pending = 0; /* clear back-to-back write detection */
|
||||
|
||||
/* okay, what we came here to do... */
|
||||
|
||||
/* if we got here, we should have wire protocol ops set on the wsi */
|
||||
assert(wsi->role_ops);
|
||||
|
||||
// lwsl_notice("%s: %s: wsistate 0x%x\n", __func__, wsi->role_ops->name,
|
||||
// wsi->wsistate);
|
||||
|
||||
switch ((wsi->role_ops->handle_POLLIN)(pt, wsi, pollfd)) {
|
||||
case LWS_HPI_RET_WSI_ALREADY_DIED:
|
||||
return 1;
|
||||
case LWS_HPI_RET_HANDLED:
|
||||
break;
|
||||
case LWS_HPI_RET_PLEASE_CLOSE_ME:
|
||||
close_and_handled:
|
||||
lwsl_debug("%p: Close and handled\n", wsi);
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"close_and_handled");
|
||||
#if defined(_DEBUG) && defined(LWS_WITH_LIBUV)
|
||||
/*
|
||||
* confirm close has no problem being called again while
|
||||
* it waits for libuv service to complete the first async
|
||||
* close
|
||||
*/
|
||||
if (context->event_loop_ops == &event_loop_ops_uv)
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"close_and_handled uv repeat test");
|
||||
#endif
|
||||
/*
|
||||
* pollfd may point to something else after the close
|
||||
* due to pollfd swapping scheme on delete on some platforms
|
||||
* we can't clear revents now because it'd be the wrong guy's
|
||||
* revents
|
||||
*/
|
||||
return 1;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
#if defined(LWS_WITH_TLS)
|
||||
handled:
|
||||
#endif
|
||||
pollfd->revents = 0;
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_hrtimer_service(pt);
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
|
||||
{
|
||||
return lws_service_fd_tsi(context, pollfd, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int n;
|
||||
|
||||
if (!context)
|
||||
return 1;
|
||||
|
||||
pt->inside_service = 1;
|
||||
|
||||
if (context->event_loop_ops->run_pt) {
|
||||
/* we are configured for an event loop */
|
||||
context->event_loop_ops->run_pt(context, 0);
|
||||
|
||||
pt->inside_service = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
n = lws_plat_service(context, timeout_ms);
|
||||
|
||||
pt->inside_service = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
int n;
|
||||
|
||||
pt->inside_service = 1;
|
||||
|
||||
if (context->event_loop_ops->run_pt) {
|
||||
/* we are configured for an event loop */
|
||||
context->event_loop_ops->run_pt(context, tsi);
|
||||
|
||||
pt->inside_service = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = _lws_plat_service_tsi(context, timeout_ms, tsi);
|
||||
|
||||
pt->inside_service = 0;
|
||||
|
||||
return n;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h if LWS_ROLE_WS
|
||||
*/
|
||||
|
||||
#include <core/private.h>
|
||||
|
||||
struct lws_event_loop_ops event_loop_ops_poll = {
|
||||
/* name */ "poll",
|
||||
/* init_context */ NULL,
|
||||
/* destroy_context1 */ NULL,
|
||||
/* destroy_context2 */ NULL,
|
||||
/* init_vhost_listen_wsi */ NULL,
|
||||
/* init_pt */ NULL,
|
||||
/* wsi_logical_close */ NULL,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ NULL,
|
||||
/* io */ NULL,
|
||||
/* run */ NULL,
|
||||
/* destroy_pt */ NULL,
|
||||
/* destroy wsi */ NULL,
|
||||
|
||||
/* periodic_events_available */ 1,
|
||||
};
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
*/
|
||||
|
||||
extern struct lws_event_loop_ops event_loop_ops_poll;
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h
|
||||
*/
|
||||
|
||||
struct lws_event_loop_ops {
|
||||
const char *name;
|
||||
/* event loop-specific context init during context creation */
|
||||
int (*init_context)(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info);
|
||||
/* called during lws_destroy_context */
|
||||
int (*destroy_context1)(struct lws_context *context);
|
||||
/* called during lws_destroy_context2 */
|
||||
int (*destroy_context2)(struct lws_context *context);
|
||||
/* init vhost listening wsi */
|
||||
int (*init_vhost_listen_wsi)(struct lws *wsi);
|
||||
/* init the event loop for a pt */
|
||||
int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
|
||||
/* called at end of first phase of close_free_wsi() */
|
||||
int (*wsi_logical_close)(struct lws *wsi);
|
||||
/* return nonzero if client connect not allowed */
|
||||
int (*check_client_connect_ok)(struct lws *wsi);
|
||||
/* close handle manually */
|
||||
void (*close_handle_manually)(struct lws *wsi);
|
||||
/* event loop accept processing */
|
||||
void (*accept)(struct lws *wsi);
|
||||
/* control wsi active events */
|
||||
void (*io)(struct lws *wsi, int flags);
|
||||
/* run the event loop for a pt */
|
||||
void (*run_pt)(struct lws_context *context, int tsi);
|
||||
/* called before pt is destroyed */
|
||||
void (*destroy_pt)(struct lws_context *context, int tsi);
|
||||
/* called just before wsi is freed */
|
||||
void (*destroy_wsi)(struct lws *wsi);
|
||||
|
||||
unsigned int periodic_events_available:1;
|
||||
};
|
||||
|
||||
/* bring in event libs private declarations */
|
||||
|
||||
#if defined(LWS_WITH_POLL)
|
||||
#include "event-libs/poll/private.h"
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_LIBUV)
|
||||
#include "event-libs/libuv/private.h"
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_LIBEVENT)
|
||||
#include "event-libs/libevent/private.h"
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_LIBEV)
|
||||
#include "event-libs/libev/private.h"
|
||||
#endif
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
diff --git a/thirdparty/libwebsockets/plat/lws-plat-unix.c b/thirdparty/libwebsockets/plat/lws-plat-unix.c
|
||||
index 7dba3bd82..d1bca8b5d 100644
|
||||
--- a/thirdparty/libwebsockets/plat/lws-plat-unix.c
|
||||
+++ b/thirdparty/libwebsockets/plat/lws-plat-unix.c
|
||||
@@ -328,6 +328,11 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
|
||||
+#ifdef LWS_WITH_IPV6
|
||||
+ optval = 0;
|
||||
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&optval, optlen);
|
||||
+#endif
|
||||
+
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
diff --git a/thirdparty/libwebsockets/plat/lws-plat-win.c b/thirdparty/libwebsockets/plat/lws-plat-win.c
|
||||
index 1850b6425..26caab2cd 100644
|
||||
--- a/thirdparty/libwebsockets/plat/lws-plat-win.c
|
||||
+++ b/thirdparty/libwebsockets/plat/lws-plat-win.c
|
||||
@@ -348,6 +348,11 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
|
||||
struct protoent *tcp_proto;
|
||||
#endif
|
||||
|
||||
+#ifdef LWS_WITH_IPV6
|
||||
+ optval = 0;
|
||||
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&optval, optlen);
|
||||
+#endif
|
||||
+
|
||||
if (vhost->ka_time) {
|
||||
/* enable keepalive on this socket */
|
||||
optval = 1;
|
File diff suppressed because it is too large
Load Diff
|
@ -1,195 +0,0 @@
|
|||
/* lws_config.h Generated from lws_config.h.in */
|
||||
|
||||
/* GODOT ADDITION */
|
||||
#ifndef DEBUG_ENABLED
|
||||
#define LWS_WITH_NO_LOGS
|
||||
#endif
|
||||
/* END GODOT ADDITION */
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LWS_INSTALL_DATADIR "/usr/local/share"
|
||||
|
||||
#define LWS_ROLE_H1
|
||||
#define LWS_ROLE_WS
|
||||
#define LWS_ROLE_RAW
|
||||
/* #undef LWS_ROLE_H2 */
|
||||
/* #undef LWS_ROLE_CGI */
|
||||
|
||||
/* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL.
|
||||
* LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
|
||||
/* #undef USE_WOLFSSL */
|
||||
|
||||
/* Also define to 1 (in addition to USE_WOLFSSL) when using the
|
||||
(older) CyaSSL library */
|
||||
/* #undef USE_OLD_CYASSL */
|
||||
/* #undef LWS_WITH_BORINGSSL */
|
||||
|
||||
#define LWS_WITH_MBEDTLS
|
||||
/* #undef LWS_WITH_POLARSSL */
|
||||
/* #undef LWS_WITH_ESP32 */
|
||||
|
||||
/* #undef LWS_WITH_PLUGINS */
|
||||
/* #undef LWS_WITH_NO_LOGS */
|
||||
|
||||
/* The Libwebsocket version */
|
||||
#define LWS_LIBRARY_VERSION "3.0.0"
|
||||
|
||||
#define LWS_LIBRARY_VERSION_MAJOR 3
|
||||
#define LWS_LIBRARY_VERSION_MINOR 0
|
||||
#define LWS_LIBRARY_VERSION_PATCH 0
|
||||
/* LWS_LIBRARY_VERSION_NUMBER looks like 1005001 for e.g. version 1.5.1 */
|
||||
#define LWS_LIBRARY_VERSION_NUMBER (LWS_LIBRARY_VERSION_MAJOR*1000000)+(LWS_LIBRARY_VERSION_MINOR*1000)+LWS_LIBRARY_VERSION_PATCH
|
||||
|
||||
/* The current git commit hash that we're building from */
|
||||
#define LWS_BUILD_HASH "v2.0.0-948-geaa935a8"
|
||||
|
||||
/* Build with OpenSSL support ... alias of LWS_WITH_TLS for compatibility*/
|
||||
#define LWS_OPENSSL_SUPPORT
|
||||
#define LWS_WITH_TLS
|
||||
|
||||
/* 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. */
|
||||
/* #undef LWS_OPENSSL_CLIENT_CERTS "../share" */
|
||||
|
||||
/* Turn off websocket extensions */
|
||||
#define LWS_WITHOUT_EXTENSIONS
|
||||
|
||||
/* notice if client or server gone */
|
||||
/* #undef LWS_WITHOUT_SERVER */
|
||||
/* #undef LWS_WITHOUT_CLIENT */
|
||||
|
||||
#define LWS_WITH_POLL
|
||||
|
||||
/* Enable libev io loop */
|
||||
/* #undef LWS_WITH_LIBEV */
|
||||
|
||||
/* Enable libuv io loop */
|
||||
/* #undef LWS_WITH_LIBUV */
|
||||
|
||||
/* Enable libevent io loop */
|
||||
/* #undef LWS_WITH_LIBEVENT */
|
||||
|
||||
/* Build with support for ipv6 */
|
||||
/* Everywhere, except in OpenBSD which does not support dual stacking */
|
||||
#if !defined(__OpenBSD__)
|
||||
#define LWS_WITH_IPV6
|
||||
#endif
|
||||
|
||||
/* Build with support for UNIX domain socket */
|
||||
/* #undef LWS_WITH_UNIX_SOCK */
|
||||
|
||||
/* Build with support for HTTP2 */
|
||||
/* #undef LWS_WITH_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 */
|
||||
/* #undef 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 */
|
||||
|
||||
/* use SHA1() not internal libwebsockets_SHA1 */
|
||||
/* #undef LWS_SHA1_USE_OPENSSL_NAME */
|
||||
|
||||
/* SSL server using ECDH certificate */
|
||||
/* #undef LWS_SSL_SERVER_WITH_ECDH_CERT */
|
||||
/* #undef LWS_HAVE_SSL_CTX_set1_param */
|
||||
#define LWS_HAVE_X509_VERIFY_PARAM_set1_host
|
||||
/* #undef LWS_HAVE_RSA_SET0_KEY */
|
||||
/* #undef LWS_HAVE_X509_get_key_usage */
|
||||
/* #undef LWS_HAVE_SSL_CTX_get0_certificate */
|
||||
|
||||
/* #undef LWS_HAVE_UV_VERSION_H */
|
||||
/* #undef LWS_HAVE_PTHREAD_H */
|
||||
|
||||
/* CGI apis */
|
||||
/* #undef LWS_WITH_CGI */
|
||||
|
||||
/* whether the Openssl is recent enough, and / or built with, ecdh */
|
||||
/* #undef LWS_HAVE_OPENSSL_ECDH_H */
|
||||
|
||||
/* HTTP Proxy support */
|
||||
/* #undef LWS_WITH_HTTP_PROXY */
|
||||
|
||||
/* HTTP Ranges support */
|
||||
/* #undef LWS_WITH_RANGES */
|
||||
|
||||
/* Http access log support */
|
||||
/* #undef LWS_WITH_ACCESS_LOG */
|
||||
/* #undef LWS_WITH_SERVER_STATUS */
|
||||
|
||||
/* #undef LWS_WITH_STATEFUL_URLDECODE */
|
||||
/* #undef LWS_WITH_PEER_LIMITS */
|
||||
|
||||
/* Maximum supported service threads */
|
||||
#define LWS_MAX_SMP 1
|
||||
|
||||
/* Lightweight JSON Parser */
|
||||
/* #undef LWS_WITH_LEJP */
|
||||
|
||||
/* SMTP */
|
||||
/* #undef LWS_WITH_SMTP */
|
||||
|
||||
/* OPTEE */
|
||||
/* #undef LWS_PLAT_OPTEE */
|
||||
|
||||
/* ZIP FOPS */
|
||||
/* #undef LWS_WITH_ZIP_FOPS */
|
||||
#define LWS_HAVE_STDINT_H
|
||||
|
||||
/* #undef LWS_AVOID_SIGPIPE_IGN */
|
||||
|
||||
/* #undef LWS_FALLBACK_GETHOSTBYNAME */
|
||||
|
||||
/* #undef LWS_WITH_STATS */
|
||||
/* #undef LWS_WITH_SOCKS5 */
|
||||
|
||||
/* #undef LWS_HAVE_SYS_CAPABILITY_H */
|
||||
/* #undef LWS_HAVE_LIBCAP */
|
||||
|
||||
#define LWS_HAVE_ATOLL
|
||||
/* #undef LWS_HAVE__ATOI64 */
|
||||
/* #undef LWS_HAVE__STAT32I64 */
|
||||
|
||||
/* #undef LWS_WITH_JWS */
|
||||
/* #undef LWS_WITH_ACME */
|
||||
/* #undef LWS_WITH_SELFTESTS */
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
|
||||
#define LWS_HAVE_MALLOC_H
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__HAIKU__)
|
||||
#define LWS_HAVE_PIPE2
|
||||
#endif
|
||||
|
||||
/* OpenSSL various APIs */
|
||||
|
||||
#define LWS_HAVE_TLS_CLIENT_METHOD
|
||||
/* #undef LWS_HAVE_TLSV1_2_CLIENT_METHOD */
|
||||
/* #undef LWS_HAVE_SSL_SET_INFO_CALLBACK */
|
||||
/* #undef LWS_HAVE_SSL_EXTRA_CHAIN_CERTS */
|
||||
/* #undef LWS_HAVE_SSL_get0_alpn_selected */
|
||||
/* #undef LWS_HAVE_SSL_set_alpn_protos */
|
||||
|
||||
#define LWS_HAS_INTPTR_T
|
||||
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
/* lws_config_private.h.in. Private compilation options. */
|
||||
#ifndef DEBUG_ENABLED
|
||||
#define NDEBUG
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#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 */
|
||||
|
||||
/* Define to 1 if you have the `bzero' function. */
|
||||
#define LWS_HAVE_BZERO
|
||||
/* Windows has no bzero function */
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#undef LWS_HAVE_BZERO
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define LWS_HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define LWS_HAVE_FCNTL_H
|
||||
#ifdef NO_FCNTL
|
||||
#undef LWS_HAVE_FCNTL_H
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#define LWS_HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `getenv’ function. */
|
||||
#define LWS_HAVE_GETENV
|
||||
|
||||
/* Define to 1 if you have the <in6addr.h> header file. */
|
||||
/* #undef LWS_HAVE_IN6ADDR_H */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define LWS_HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
/* #undef LWS_HAVE_LIBSSL */
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#define LWS_HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define LWS_HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define LWS_HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#define LWS_HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#define LWS_HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#define LWS_HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define LWS_HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define LWS_HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define LWS_HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define LWS_HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define LWS_HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||
#define LWS_HAVE_SYS_PRCTL_H
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||||
#undef LWS_HAVE_SYS_PRCTL_H
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define LWS_HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
/* #undef LWS_HAVE_SYS_SOCKIO_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define LWS_HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define LWS_HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define LWS_HAVE_UNISTD_H
|
||||
|
||||
#define LWS_HAVE_TCP_USER_TIMEOUT
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#define LWS_HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
/* #undef LWS_HAVE_VFORK_H */
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#define LWS_HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#define LWS_HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if execvpe() exists */
|
||||
#define LWS_HAVE_EXECVPE
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#define LWS_HAVE_ZLIB_H
|
||||
|
||||
#define LWS_HAVE_GETLOADAVG
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR // We're not using libtool
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
/* #undef malloc */
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
/* #undef realloc */
|
||||
|
||||
/* Define to 1 if we have getifaddrs */
|
||||
#define LWS_HAVE_GETIFADDRS
|
||||
#if defined(ANDROID_ENABLED)
|
||||
#undef LWS_HAVE_GETIFADDRS
|
||||
#define LWS_BUILTIN_GETIFADDRS
|
||||
#endif
|
||||
|
||||
/* Define if the inline keyword doesn't exist. */
|
||||
/* #undef inline */
|
||||
|
||||
|
|
@ -1,242 +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.1 + SLE like the rest of lws
|
||||
* since he explicitly 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 "core/private.h"
|
||||
|
||||
static const char encode_orig[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char encode_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
|
||||
"$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
|
||||
|
||||
static int
|
||||
_lws_b64_encode_string(const char *encode, 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;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
|
||||
{
|
||||
return _lws_b64_encode_string(encode_orig, in, in_len, out, out_size);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size)
|
||||
{
|
||||
return _lws_b64_encode_string(encode_url, in, in_len, out, out_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns length of decoded string in out, or -1 if out was too small
|
||||
* according to out_size
|
||||
*
|
||||
* Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
|
||||
* the first NUL in the input.
|
||||
*/
|
||||
|
||||
static int
|
||||
_lws_b64_decode_string(const char *in, int in_len, char *out, int out_size)
|
||||
{
|
||||
int len, i, c = 0, done = 0;
|
||||
unsigned char v, quad[4];
|
||||
|
||||
while (in_len && *in) {
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < 4 && in_len && *in; i++) {
|
||||
|
||||
v = 0;
|
||||
c = 0;
|
||||
while (in_len && *in && !v) {
|
||||
c = v = *in++;
|
||||
in_len--;
|
||||
/* support the url base64 variant too */
|
||||
if (v == '-')
|
||||
c = v = '+';
|
||||
if (v == '_')
|
||||
c = v = '/';
|
||||
v = (v < 43 || v > 122) ? 0 : decode[v - 43];
|
||||
if (v)
|
||||
v = (v == '$') ? 0 : v - 61;
|
||||
}
|
||||
if (c) {
|
||||
len++;
|
||||
if (v)
|
||||
quad[i] = v - 1;
|
||||
} else
|
||||
quad[i] = 0;
|
||||
}
|
||||
|
||||
if (out_size < (done + len - 1))
|
||||
/* out buffer is too small */
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* "The '==' sequence indicates that the last group contained
|
||||
* only one byte, and '=' indicates that it contained two
|
||||
* bytes." (wikipedia)
|
||||
*/
|
||||
|
||||
if ((!in_len || !*in) && c == '=')
|
||||
len--;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_decode_string(const char *in, char *out, int out_size)
|
||||
{
|
||||
return _lws_b64_decode_string(in, -1, out, out_size);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size)
|
||||
{
|
||||
return _lws_b64_decode_string(in, in_len, out, out_size);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
lws_b64_selftest(void)
|
||||
{
|
||||
char buf[64];
|
||||
unsigned int n, r = 0;
|
||||
unsigned int test;
|
||||
/* examples from https://en.wikipedia.org/wiki/Base64 */
|
||||
static const char * const plaintext[] = {
|
||||
"any carnal pleasure.",
|
||||
"any carnal pleasure",
|
||||
"any carnal pleasur",
|
||||
"any carnal pleasu",
|
||||
"any carnal pleas",
|
||||
"Admin:kloikloi"
|
||||
};
|
||||
static const char * const coded[] = {
|
||||
"YW55IGNhcm5hbCBwbGVhc3VyZS4=",
|
||||
"YW55IGNhcm5hbCBwbGVhc3VyZQ==",
|
||||
"YW55IGNhcm5hbCBwbGVhc3Vy",
|
||||
"YW55IGNhcm5hbCBwbGVhc3U=",
|
||||
"YW55IGNhcm5hbCBwbGVhcw==",
|
||||
"QWRtaW46a2xvaWtsb2k="
|
||||
};
|
||||
|
||||
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);
|
||||
r = -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' / '%s', %d / %d\n",
|
||||
test, buf, plaintext[test], n, strlen(plaintext[test]));
|
||||
r = -1;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_notice("Base 64 selftests passed\n");
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
|
@ -1,270 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000 - 2001 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.
|
||||
*
|
||||
* originally downloaded from
|
||||
*
|
||||
* http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include "core/private.h"
|
||||
|
||||
#ifdef LWS_HAVE_SYS_SOCKIO_H
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#ifdef LWS_HAVE_NETINET_IN6_VAR_H
|
||||
#include <netinet/in6_var.h>
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#include "getifaddrs.h"
|
||||
|
||||
static int
|
||||
getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,
|
||||
size_t ifreq_sz)
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
struct ifconf ifconf;
|
||||
char *p;
|
||||
size_t sz;
|
||||
struct sockaddr sa_zero;
|
||||
struct ifreq *ifr;
|
||||
struct ifaddrs *start, **end = &start;
|
||||
|
||||
buf = NULL;
|
||||
|
||||
memset(&sa_zero, 0, sizeof(sa_zero));
|
||||
fd = socket(af, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
buf_size = 8192;
|
||||
for (;;) {
|
||||
buf = lws_zalloc(buf_size, "getifaddrs2");
|
||||
if (buf == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto error_out;
|
||||
}
|
||||
ifconf.ifc_len = buf_size;
|
||||
ifconf.ifc_buf = buf;
|
||||
|
||||
/*
|
||||
* Solaris returns EINVAL when the buffer is too small.
|
||||
*/
|
||||
if (ioctl(fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
|
||||
ret = errno;
|
||||
goto error_out;
|
||||
}
|
||||
/*
|
||||
* Can the difference between a full and a overfull buf
|
||||
* be determined?
|
||||
*/
|
||||
|
||||
if (ifconf.ifc_len < (int)buf_size)
|
||||
break;
|
||||
lws_free(buf);
|
||||
buf_size *= 2;
|
||||
}
|
||||
|
||||
for (p = ifconf.ifc_buf; p < ifconf.ifc_buf + ifconf.ifc_len; p += sz) {
|
||||
struct ifreq ifreq;
|
||||
struct sockaddr *sa;
|
||||
size_t salen;
|
||||
|
||||
ifr = (struct ifreq *)p;
|
||||
sa = &ifr->ifr_addr;
|
||||
|
||||
sz = ifreq_sz;
|
||||
salen = sizeof(struct sockaddr);
|
||||
#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
salen = sa->sa_len;
|
||||
sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
|
||||
#endif
|
||||
#ifdef SA_LEN
|
||||
salen = SA_LEN(sa);
|
||||
sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
|
||||
#endif
|
||||
memset(&ifreq, 0, sizeof(ifreq));
|
||||
memcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
|
||||
|
||||
if (ioctl(fd, siocgifflags, &ifreq) < 0) {
|
||||
ret = errno;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
*end = lws_malloc(sizeof(**end), "getifaddrs");
|
||||
|
||||
(*end)->ifa_next = NULL;
|
||||
(*end)->ifa_name = strdup(ifr->ifr_name);
|
||||
(*end)->ifa_flags = ifreq.ifr_flags;
|
||||
(*end)->ifa_addr = lws_malloc(salen, "getifaddrs");
|
||||
memcpy((*end)->ifa_addr, sa, salen);
|
||||
(*end)->ifa_netmask = NULL;
|
||||
|
||||
#if 0
|
||||
/* fix these when we actually need them */
|
||||
if (ifreq.ifr_flags & IFF_BROADCAST) {
|
||||
(*end)->ifa_broadaddr =
|
||||
lws_malloc(sizeof(ifr->ifr_broadaddr), "getifaddrs");
|
||||
memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
|
||||
sizeof(ifr->ifr_broadaddr));
|
||||
} else if (ifreq.ifr_flags & IFF_POINTOPOINT) {
|
||||
(*end)->ifa_dstaddr =
|
||||
lws_malloc(sizeof(ifr->ifr_dstaddr), "getifaddrs");
|
||||
memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
|
||||
sizeof(ifr->ifr_dstaddr));
|
||||
} else
|
||||
(*end)->ifa_dstaddr = NULL;
|
||||
#else
|
||||
(*end)->ifa_dstaddr = NULL;
|
||||
#endif
|
||||
(*end)->ifa_data = NULL;
|
||||
|
||||
end = &(*end)->ifa_next;
|
||||
|
||||
}
|
||||
*ifap = start;
|
||||
close(fd);
|
||||
lws_free(buf);
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
close(fd);
|
||||
lws_free(buf);
|
||||
errno = ret;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int ret = -1;
|
||||
errno = ENXIO;
|
||||
#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
|
||||
sizeof(struct in6_ifreq));
|
||||
#endif
|
||||
#if defined(LWS_HAVE_IPV6) && defined(SIOCGIFCONF)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
freeifaddrs(struct ifaddrs *ifp)
|
||||
{
|
||||
struct ifaddrs *p, *q;
|
||||
|
||||
for (p = ifp; p; ) {
|
||||
lws_free(p->ifa_name);
|
||||
lws_free(p->ifa_addr);
|
||||
lws_free(p->ifa_dstaddr);
|
||||
lws_free(p->ifa_netmask);
|
||||
lws_free(p->ifa_data);
|
||||
q = p;
|
||||
p = p->ifa_next;
|
||||
lws_free(q);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
void
|
||||
print_addr(const char *s, struct sockaddr *sa)
|
||||
{
|
||||
int i;
|
||||
printf(" %s=%d/", s, sa->sa_family);
|
||||
#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
for (i = 0;
|
||||
i < sa->sa_len - ((lws_intptr_t)sa->sa_data - (lws_intptr_t)&sa->sa_family); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#else
|
||||
for (i = 0; i < sizeof(sa->sa_data); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
print_ifaddrs(struct ifaddrs *x)
|
||||
{
|
||||
struct ifaddrs *p;
|
||||
|
||||
for (p = x; p; p = p->ifa_next) {
|
||||
printf("%s\n", p->ifa_name);
|
||||
printf(" flags=%x\n", p->ifa_flags);
|
||||
if (p->ifa_addr)
|
||||
print_addr("addr", p->ifa_addr);
|
||||
if (p->ifa_dstaddr)
|
||||
print_addr("dstaddr", p->ifa_dstaddr);
|
||||
if (p->ifa_netmask)
|
||||
print_addr("netmask", p->ifa_netmask);
|
||||
printf(" %p\n", p->ifa_data);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
struct ifaddrs *a = NULL, *b;
|
||||
getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
print_ifaddrs(a);
|
||||
printf("---\n");
|
||||
getifaddrs(&b);
|
||||
print_ifaddrs(b);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,80 +0,0 @@
|
|||
#ifndef LWS_HAVE_GETIFADDRS
|
||||
#define LWS_HAVE_GETIFADDRS 0
|
||||
#endif
|
||||
|
||||
#if LWS_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
|
|
@ -1,753 +0,0 @@
|
|||
/*
|
||||
* Lightweight Embedded JSON Parser
|
||||
*
|
||||
* Copyright (C) 2013-2017 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 <libwebsockets.h>
|
||||
#include "core/private.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* lejp_construct - prepare a struct lejp_ctx for use
|
||||
*
|
||||
* \param ctx: pointer to your struct lejp_ctx
|
||||
* \param callback: your user callback which will received parsed tokens
|
||||
* \param user: optional user data pointer untouched by lejp
|
||||
* \param paths: your array of name elements you are interested in
|
||||
* \param count_paths: LWS_ARRAY_SIZE() of @paths
|
||||
*
|
||||
* Prepares your context struct for use with lejp
|
||||
*/
|
||||
|
||||
void
|
||||
lejp_construct(struct lejp_ctx *ctx,
|
||||
signed char (*callback)(struct lejp_ctx *ctx, char reason), void *user,
|
||||
const char * const *paths, unsigned char count_paths)
|
||||
{
|
||||
ctx->st[0].s = 0;
|
||||
ctx->st[0].p = 0;
|
||||
ctx->st[0].i = 0;
|
||||
ctx->st[0].b = 0;
|
||||
ctx->sp = 0;
|
||||
ctx->ipos = 0;
|
||||
ctx->ppos = 0;
|
||||
ctx->path_match = 0;
|
||||
ctx->path[0] = '\0';
|
||||
ctx->callback = callback;
|
||||
ctx->user = user;
|
||||
ctx->paths = paths;
|
||||
ctx->count_paths = count_paths;
|
||||
ctx->line = 1;
|
||||
ctx->callback(ctx, LEJPCB_CONSTRUCTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* lejp_destruct - retire a previously constructed struct lejp_ctx
|
||||
*
|
||||
* \param ctx: pointer to your struct lejp_ctx
|
||||
*
|
||||
* lejp does not perform any allocations, but since your user code might, this
|
||||
* provides a one-time LEJPCB_DESTRUCTED callback at destruction time where
|
||||
* you can clean up in your callback.
|
||||
*/
|
||||
|
||||
void
|
||||
lejp_destruct(struct lejp_ctx *ctx)
|
||||
{
|
||||
/* no allocations... just let callback know what it happening */
|
||||
ctx->callback(ctx, LEJPCB_DESTRUCTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* lejp_change_callback - switch to a different callback from now on
|
||||
*
|
||||
* \param ctx: pointer to your struct lejp_ctx
|
||||
* \param callback: your user callback which will received parsed tokens
|
||||
*
|
||||
* This tells the old callback it was destroyed, in case you want to take any
|
||||
* action because that callback "lost focus", then changes to the new
|
||||
* callback and tells it first that it was constructed, and then started.
|
||||
*
|
||||
* Changing callback is a cheap and powerful trick to split out handlers
|
||||
* according to information earlier in the parse. For example you may have
|
||||
* a JSON pair "schema" whose value defines what can be expected for the rest
|
||||
* of the JSON. Rather than having one huge callback for all cases, you can
|
||||
* have an initial one looking for "schema" which then calls
|
||||
* lejp_change_callback() to a handler specific for the schema.
|
||||
*
|
||||
* Notice that afterwards, you need to construct the context again anyway to
|
||||
* parse another JSON object, and the callback is reset then to the main,
|
||||
* schema-interpreting one. The construction action is very lightweight.
|
||||
*/
|
||||
|
||||
void
|
||||
lejp_change_callback(struct lejp_ctx *ctx,
|
||||
signed char (*callback)(struct lejp_ctx *ctx, char reason))
|
||||
{
|
||||
ctx->callback(ctx, LEJPCB_DESTRUCTED);
|
||||
ctx->callback = callback;
|
||||
ctx->callback(ctx, LEJPCB_CONSTRUCTED);
|
||||
ctx->callback(ctx, LEJPCB_START);
|
||||
}
|
||||
|
||||
static void
|
||||
lejp_check_path_match(struct lejp_ctx *ctx)
|
||||
{
|
||||
const char *p, *q;
|
||||
int n;
|
||||
|
||||
/* we only need to check if a match is not active */
|
||||
for (n = 0; !ctx->path_match && n < ctx->count_paths; n++) {
|
||||
ctx->wildcount = 0;
|
||||
p = ctx->path;
|
||||
q = ctx->paths[n];
|
||||
while (*p && *q) {
|
||||
if (*q != '*') {
|
||||
if (*p != *q)
|
||||
break;
|
||||
p++;
|
||||
q++;
|
||||
continue;
|
||||
}
|
||||
ctx->wild[ctx->wildcount++] = p - ctx->path;
|
||||
q++;
|
||||
/*
|
||||
* if * has something after it, match to .
|
||||
* if ends with *, eat everything.
|
||||
* This implies match sequences must be ordered like
|
||||
* x.*.*
|
||||
* x.*
|
||||
* if both options are possible
|
||||
*/
|
||||
while (*p && (*p != '.' || !*q))
|
||||
p++;
|
||||
}
|
||||
if (*p || *q)
|
||||
continue;
|
||||
|
||||
ctx->path_match = n + 1;
|
||||
ctx->path_match_len = ctx->ppos;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx->path_match)
|
||||
ctx->wildcount = 0;
|
||||
}
|
||||
|
||||
int
|
||||
lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (wildcard >= ctx->wildcount || !len)
|
||||
return 0;
|
||||
|
||||
n = ctx->wild[wildcard];
|
||||
|
||||
while (--len && n < ctx->ppos &&
|
||||
(n == ctx->wild[wildcard] || ctx->path[n] != '.'))
|
||||
*dest++ = ctx->path[n++];
|
||||
|
||||
*dest = '\0';
|
||||
n++;
|
||||
|
||||
return n - ctx->wild[wildcard];
|
||||
}
|
||||
|
||||
/**
|
||||
* lejp_parse - interpret some more incoming data incrementally
|
||||
*
|
||||
* \param ctx: previously constructed parsing context
|
||||
* \param json: char buffer with the new data to interpret
|
||||
* \param len: amount of data in the buffer
|
||||
*
|
||||
* Because lejp is a stream parser, it incrementally parses as new data
|
||||
* becomes available, maintaining all state in the context struct. So an
|
||||
* incomplete JSON is a normal situation, getting you a LEJP_CONTINUE
|
||||
* return, signalling there's no error but to call again with more data when
|
||||
* it comes to complete the parsing. Successful parsing completes with a
|
||||
* 0 or positive integer indicating how much of the last input buffer was
|
||||
* unused.
|
||||
*/
|
||||
|
||||
int
|
||||
lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
||||
{
|
||||
unsigned char c, n, s, ret = LEJP_REJECT_UNKNOWN;
|
||||
static const char esc_char[] = "\"\\/bfnrt";
|
||||
static const char esc_tran[] = "\"\\/\b\f\n\r\t";
|
||||
static const char tokens[] = "rue alse ull ";
|
||||
|
||||
if (!ctx->sp && !ctx->ppos)
|
||||
ctx->callback(ctx, LEJPCB_START);
|
||||
|
||||
while (len--) {
|
||||
c = *json++;
|
||||
s = ctx->st[ctx->sp].s;
|
||||
|
||||
/* skip whitespace unless we should care */
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
|
||||
if (c == '\n') {
|
||||
ctx->line++;
|
||||
ctx->st[ctx->sp].s &= ~LEJP_FLAG_WS_COMMENTLINE;
|
||||
}
|
||||
if (!(s & LEJP_FLAG_WS_KEEP)) {
|
||||
if (c == '#')
|
||||
ctx->st[ctx->sp].s |=
|
||||
LEJP_FLAG_WS_COMMENTLINE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->st[ctx->sp].s & LEJP_FLAG_WS_COMMENTLINE)
|
||||
continue;
|
||||
|
||||
switch (s) {
|
||||
case LEJP_IDLE:
|
||||
if (c != '{') {
|
||||
ret = LEJP_REJECT_IDLE_NO_BRACE;
|
||||
goto reject;
|
||||
}
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
ctx->st[ctx->sp].s = LEJP_MEMBERS;
|
||||
break;
|
||||
case LEJP_MEMBERS:
|
||||
if (c == '}') {
|
||||
ctx->st[ctx->sp].s = LEJP_IDLE;
|
||||
ret = LEJP_REJECT_MEMBERS_NO_CLOSE;
|
||||
goto reject;
|
||||
}
|
||||
ctx->st[ctx->sp].s = LEJP_M_P;
|
||||
goto redo_character;
|
||||
case LEJP_M_P:
|
||||
if (c != '\"') {
|
||||
ret = LEJP_REJECT_MP_NO_OPEN_QUOTE;
|
||||
goto reject;
|
||||
}
|
||||
/* push */
|
||||
ctx->st[ctx->sp].s = LEJP_MP_DELIM;
|
||||
c = LEJP_MP_STRING;
|
||||
goto add_stack_level;
|
||||
|
||||
case LEJP_MP_STRING:
|
||||
if (c == '\"') {
|
||||
if (!ctx->sp) { /* JSON can't end on quote */
|
||||
ret = LEJP_REJECT_MP_STRING_UNDERRUN;
|
||||
goto reject;
|
||||
}
|
||||
if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
|
||||
ctx->buf[ctx->npos] = '\0';
|
||||
if (ctx->callback(ctx,
|
||||
LEJPCB_VAL_STR_END) < 0) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
}
|
||||
/* pop */
|
||||
ctx->sp--;
|
||||
break;
|
||||
}
|
||||
if (c == '\\') {
|
||||
ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC;
|
||||
break;
|
||||
}
|
||||
if (c < ' ') {/* "control characters" not allowed */
|
||||
ret = LEJP_REJECT_MP_ILLEGAL_CTRL;
|
||||
goto reject;
|
||||
}
|
||||
goto emit_string_char;
|
||||
|
||||
case LEJP_MP_STRING_ESC:
|
||||
if (c == 'u') {
|
||||
ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC_U1;
|
||||
ctx->uni = 0;
|
||||
break;
|
||||
}
|
||||
for (n = 0; n < sizeof(esc_char); n++) {
|
||||
if (c != esc_char[n])
|
||||
continue;
|
||||
/* found it */
|
||||
c = esc_tran[n];
|
||||
ctx->st[ctx->sp].s = LEJP_MP_STRING;
|
||||
goto emit_string_char;
|
||||
}
|
||||
ret = LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;
|
||||
/* illegal escape char */
|
||||
goto reject;
|
||||
|
||||
case LEJP_MP_STRING_ESC_U1:
|
||||
case LEJP_MP_STRING_ESC_U2:
|
||||
case LEJP_MP_STRING_ESC_U3:
|
||||
case LEJP_MP_STRING_ESC_U4:
|
||||
ctx->uni <<= 4;
|
||||
if (c >= '0' && c <= '9')
|
||||
ctx->uni |= c - '0';
|
||||
else
|
||||
if (c >= 'a' && c <= 'f')
|
||||
ctx->uni = c - 'a' + 10;
|
||||
else
|
||||
if (c >= 'A' && c <= 'F')
|
||||
ctx->uni = c - 'A' + 10;
|
||||
else {
|
||||
ret = LEJP_REJECT_ILLEGAL_HEX;
|
||||
goto reject;
|
||||
}
|
||||
ctx->st[ctx->sp].s++;
|
||||
switch (s) {
|
||||
case LEJP_MP_STRING_ESC_U2:
|
||||
if (ctx->uni < 0x08)
|
||||
break;
|
||||
/*
|
||||
* 0x08-0xff (0x0800 - 0xffff)
|
||||
* emit 3-byte UTF-8
|
||||
*/
|
||||
c = 0xe0 | ((ctx->uni >> 4) & 0xf);
|
||||
goto emit_string_char;
|
||||
|
||||
case LEJP_MP_STRING_ESC_U3:
|
||||
if (ctx->uni >= 0x080) {
|
||||
/*
|
||||
* 0x080 - 0xfff (0x0800 - 0xffff)
|
||||
* middle 3-byte seq
|
||||
* send ....XXXXXX..
|
||||
*/
|
||||
c = 0x80 | ((ctx->uni >> 2) & 0x3f);
|
||||
goto emit_string_char;
|
||||
}
|
||||
if (ctx->uni < 0x008)
|
||||
break;
|
||||
/*
|
||||
* 0x008 - 0x7f (0x0080 - 0x07ff)
|
||||
* start 2-byte seq
|
||||
*/
|
||||
c = 0xc0 | (ctx->uni >> 2);
|
||||
goto emit_string_char;
|
||||
|
||||
case LEJP_MP_STRING_ESC_U4:
|
||||
if (ctx->uni >= 0x0080)
|
||||
/* end of 2 or 3-byte seq */
|
||||
c = 0x80 | (ctx->uni & 0x3f);
|
||||
else
|
||||
/* literal */
|
||||
c = (unsigned char)ctx->uni;
|
||||
|
||||
ctx->st[ctx->sp].s = LEJP_MP_STRING;
|
||||
goto emit_string_char;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LEJP_MP_DELIM:
|
||||
if (c != ':') {
|
||||
ret = LEJP_REJECT_MP_DELIM_MISSING_COLON;
|
||||
goto reject;
|
||||
}
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE;
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_PAIR_NAME)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
|
||||
case LEJP_MP_VALUE:
|
||||
if (c >= '0' && c <= '9') {
|
||||
ctx->npos = 0;
|
||||
ctx->dcount = 0;
|
||||
ctx->f = 0;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
|
||||
goto redo_character;
|
||||
}
|
||||
switch (c) {
|
||||
case'\"':
|
||||
/* push */
|
||||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
c = LEJP_MP_STRING;
|
||||
ctx->npos = 0;
|
||||
ctx->buf[0] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_STR_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
goto add_stack_level;
|
||||
|
||||
case '{':
|
||||
/* push */
|
||||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
c = LEJP_MEMBERS;
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
ctx->path_match = 0;
|
||||
goto add_stack_level;
|
||||
|
||||
case '[':
|
||||
/* push */
|
||||
ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
|
||||
c = LEJP_MP_VALUE;
|
||||
ctx->path[ctx->ppos++] = '[';
|
||||
ctx->path[ctx->ppos++] = ']';
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_ARRAY_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
ctx->i[ctx->ipos++] = 0;
|
||||
if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
|
||||
ret = LEJP_REJECT_MP_DELIM_ISTACK;
|
||||
goto reject;
|
||||
}
|
||||
goto add_stack_level;
|
||||
|
||||
case ']':
|
||||
/* pop */
|
||||
if (!ctx->sp) { /* JSON can't end on ] */
|
||||
ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
|
||||
goto reject;
|
||||
}
|
||||
ctx->sp--;
|
||||
if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
|
||||
ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
|
||||
goto reject;
|
||||
}
|
||||
/* drop the path [n] bit */
|
||||
if (ctx->sp) {
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->ipos = ctx->st[ctx->sp - 1].i;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
*/
|
||||
ctx->path_match = 0;
|
||||
goto array_end;
|
||||
|
||||
case 't': /* true */
|
||||
ctx->uni = 0;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
ctx->uni = 4;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
ctx->uni = 4 + 5;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
|
||||
break;
|
||||
default:
|
||||
ret = LEJP_REJECT_MP_DELIM_BAD_VALUE_START;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
|
||||
case LEJP_MP_VALUE_NUM_INT:
|
||||
if (!ctx->npos && c == '-') {
|
||||
ctx->f |= LEJP_SEEN_MINUS;
|
||||
goto append_npos;
|
||||
}
|
||||
|
||||
if (ctx->dcount < 10 && c >= '0' && c <= '9') {
|
||||
if (ctx->f & LEJP_SEEN_POINT)
|
||||
ctx->f |= LEJP_SEEN_POST_POINT;
|
||||
ctx->dcount++;
|
||||
goto append_npos;
|
||||
}
|
||||
if (c == '.') {
|
||||
if (!ctx->dcount || (ctx->f & LEJP_SEEN_POINT)) {
|
||||
ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
|
||||
goto reject;
|
||||
}
|
||||
ctx->f |= LEJP_SEEN_POINT;
|
||||
goto append_npos;
|
||||
}
|
||||
/*
|
||||
* before exponent, if we had . we must have had at
|
||||
* least one more digit
|
||||
*/
|
||||
if ((ctx->f &
|
||||
(LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) ==
|
||||
LEJP_SEEN_POINT) {
|
||||
ret = LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;
|
||||
goto reject;
|
||||
}
|
||||
if (c == 'e' || c == 'E') {
|
||||
if (ctx->f & LEJP_SEEN_EXP) {
|
||||
ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
|
||||
goto reject;
|
||||
}
|
||||
ctx->f |= LEJP_SEEN_EXP;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_EXP;
|
||||
goto append_npos;
|
||||
}
|
||||
/* if none of the above, did we even have a number? */
|
||||
if (!ctx->dcount) {
|
||||
ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
|
||||
goto reject;
|
||||
}
|
||||
|
||||
ctx->buf[ctx->npos] = '\0';
|
||||
if (ctx->f & LEJP_SEEN_POINT) {
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
} else {
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_NUM_INT)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
}
|
||||
|
||||
/* then this is the post-number character, loop */
|
||||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
goto redo_character;
|
||||
|
||||
case LEJP_MP_VALUE_NUM_EXP:
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
|
||||
if (c >= '0' && c <= '9')
|
||||
goto redo_character;
|
||||
if (c == '+' || c == '-')
|
||||
goto append_npos;
|
||||
ret = LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;
|
||||
goto reject;
|
||||
|
||||
case LEJP_MP_VALUE_TOK: /* true, false, null */
|
||||
if (c != tokens[ctx->uni]) {
|
||||
ret = LEJP_REJECT_MP_VAL_TOK_UNKNOWN;
|
||||
goto reject;
|
||||
}
|
||||
ctx->uni++;
|
||||
if (tokens[ctx->uni] != ' ')
|
||||
break;
|
||||
switch (ctx->uni) {
|
||||
case 3:
|
||||
ctx->buf[0] = '1';
|
||||
ctx->buf[1] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_TRUE)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
ctx->buf[0] = '0';
|
||||
ctx->buf[1] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_FALSE)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
ctx->buf[0] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_NULL)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
break;
|
||||
|
||||
case LEJP_MP_COMMA_OR_END:
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (c == ',') {
|
||||
/* increment this stack level's index */
|
||||
ctx->st[ctx->sp].s = LEJP_M_P;
|
||||
if (!ctx->sp) {
|
||||
ctx->ppos = 0;
|
||||
/*
|
||||
* since we came back to root level,
|
||||
* no path can still match
|
||||
*/
|
||||
ctx->path_match = 0;
|
||||
break;
|
||||
}
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
*/
|
||||
ctx->path_match = 0;
|
||||
|
||||
if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END)
|
||||
break;
|
||||
/* top level is definitely an array... */
|
||||
if (ctx->ipos)
|
||||
ctx->i[ctx->ipos - 1]++;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE;
|
||||
break;
|
||||
}
|
||||
if (c == ']') {
|
||||
if (!ctx->sp) { /* JSON can't end on ] */
|
||||
ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
|
||||
goto reject;
|
||||
}
|
||||
/* pop */
|
||||
ctx->sp--;
|
||||
if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
|
||||
ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
|
||||
goto reject;
|
||||
}
|
||||
/* drop the path [n] bit */
|
||||
if (ctx->sp) {
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->ipos = ctx->st[ctx->sp - 1].i;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
*/
|
||||
ctx->path_match = 0;
|
||||
|
||||
/* do LEJP_MP_ARRAY_END processing */
|
||||
goto redo_character;
|
||||
}
|
||||
if (c == '}') {
|
||||
if (!ctx->sp) {
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
ctx->callback(ctx, LEJPCB_COMPLETE);
|
||||
/* done, return unused amount */
|
||||
return len;
|
||||
}
|
||||
/* pop */
|
||||
ctx->sp--;
|
||||
if (ctx->sp) {
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->ipos = ctx->st[ctx->sp - 1].i;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
*/
|
||||
ctx->path_match = 0;
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
|
||||
goto reject;
|
||||
|
||||
case LEJP_MP_ARRAY_END:
|
||||
array_end:
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (c == ',') {
|
||||
/* increment this stack level's index */
|
||||
if (ctx->ipos)
|
||||
ctx->i[ctx->ipos - 1]++;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE;
|
||||
if (ctx->sp)
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
break;
|
||||
}
|
||||
if (c != ']') {
|
||||
ret = LEJP_REJECT_MP_ARRAY_END_MISSING;
|
||||
goto reject;
|
||||
}
|
||||
|
||||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
ctx->callback(ctx, LEJPCB_ARRAY_END);
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
emit_string_char:
|
||||
if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
|
||||
/* assemble the string value into chunks */
|
||||
ctx->buf[ctx->npos++] = c;
|
||||
if (ctx->npos == sizeof(ctx->buf) - 1) {
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_STR_CHUNK)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
ctx->npos = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* name part of name:value pair */
|
||||
ctx->path[ctx->ppos++] = c;
|
||||
continue;
|
||||
|
||||
add_stack_level:
|
||||
/* push on to the object stack */
|
||||
if (ctx->ppos && ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END &&
|
||||
ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
|
||||
ctx->path[ctx->ppos++] = '.';
|
||||
|
||||
ctx->st[ctx->sp].p = ctx->ppos;
|
||||
ctx->st[ctx->sp].i = ctx->ipos;
|
||||
if (++ctx->sp == LWS_ARRAY_SIZE(ctx->st)) {
|
||||
ret = LEJP_REJECT_STACK_OVERFLOW;
|
||||
goto reject;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->st[ctx->sp].s = c;
|
||||
ctx->st[ctx->sp].b = 0;
|
||||
continue;
|
||||
|
||||
append_npos:
|
||||
if (ctx->npos >= sizeof(ctx->buf)) {
|
||||
ret = LEJP_REJECT_NUM_TOO_LONG;
|
||||
goto reject;
|
||||
}
|
||||
ctx->buf[ctx->npos++] = c;
|
||||
continue;
|
||||
|
||||
redo_character:
|
||||
json--;
|
||||
len++;
|
||||
}
|
||||
|
||||
return LEJP_CONTINUE;
|
||||
|
||||
reject:
|
||||
ctx->callback(ctx, LEJPCB_FAILED);
|
||||
return ret;
|
||||
}
|
|
@ -1,300 +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 "core/private.h"
|
||||
|
||||
#ifdef LWS_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];
|
||||
uint64_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(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 += (unsigned char)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 += ((unsigned char)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 += (unsigned char)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 *
|
||||
lws_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*/
|
|
@ -1,982 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 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
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "core/private.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
|
||||
void lws_plat_apply_FD_CLOEXEC(int n)
|
||||
{
|
||||
if (n != -1)
|
||||
fcntl(n, F_SETFD, FD_CLOEXEC );
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_socket_offset(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_create(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
#if defined(LWS_HAVE_PIPE2)
|
||||
return pipe2(pt->dummy_pipe_fds, O_NONBLOCK);
|
||||
#else
|
||||
return pipe(pt->dummy_pipe_fds);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_signal(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char buf = 0;
|
||||
int n;
|
||||
|
||||
n = write(pt->dummy_pipe_fds[1], &buf, 1);
|
||||
|
||||
return n != 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_pipe_close(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
if (pt->dummy_pipe_fds[0] && pt->dummy_pipe_fds[0] != -1)
|
||||
close(pt->dummy_pipe_fds[0]);
|
||||
if (pt->dummy_pipe_fds[1] && pt->dummy_pipe_fds[1] != -1)
|
||||
close(pt->dummy_pipe_fds[1]);
|
||||
|
||||
pt->dummy_pipe_fds[0] = pt->dummy_pipe_fds[1] = -1;
|
||||
}
|
||||
|
||||
#ifdef __QNX__
|
||||
# include "netinet/tcp_var.h"
|
||||
# define TCP_KEEPINTVL TCPCTL_KEEPINTVL
|
||||
# define TCP_KEEPIDLE TCPCTL_KEEPIDLE
|
||||
# define TCP_KEEPCNT TCPCTL_KEEPCNT
|
||||
#endif
|
||||
|
||||
unsigned long long time_in_microseconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_get_random(struct lws_context *context, void *buf, int len)
|
||||
{
|
||||
return read(context->fd_random, (char *)buf, len);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_send_pipe_choked(struct lws *wsi)
|
||||
{
|
||||
struct lws_pollfd fds;
|
||||
struct lws *wsi_eff = wsi;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
wsi_eff = lws_get_network_wsi(wsi);
|
||||
#endif
|
||||
|
||||
/* the fact we checked implies we avoided back-to-back writes */
|
||||
wsi_eff->could_have_pending = 0;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (wsi_eff->trunc_len)
|
||||
return 1;
|
||||
|
||||
fds.fd = wsi_eff->desc.sockfd;
|
||||
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 lws_pollfd *fd)
|
||||
{
|
||||
return poll(fd, 1, 0);
|
||||
}
|
||||
|
||||
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 LWS_EXTERN int
|
||||
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
volatile struct lws_foreign_thread_pollfd *ftp, *next;
|
||||
volatile struct lws_context_per_thread *vpt;
|
||||
struct lws_context_per_thread *pt;
|
||||
int n = -1, m, c;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
|
||||
if (!context || !context->vhost_list)
|
||||
return 1;
|
||||
|
||||
pt = &context->pt[tsi];
|
||||
vpt = (volatile struct lws_context_per_thread *)pt;
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);
|
||||
|
||||
if (timeout_ms < 0)
|
||||
goto faked_service;
|
||||
|
||||
if (context->event_loop_ops->run_pt)
|
||||
context->event_loop_ops->run_pt(context, tsi);
|
||||
|
||||
if (!context->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
||||
memset(&_lws, 0, sizeof(_lws));
|
||||
_lws.context = context;
|
||||
|
||||
context->service_tid_detected =
|
||||
context->vhost_list->protocols[0].callback(
|
||||
&_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
context->service_tid = context->service_tid_detected;
|
||||
context->service_tid_detected = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* is there anybody with pending stuff that needs service forcing?
|
||||
*/
|
||||
if (!lws_service_adjust_timeout(context, 1, tsi)) {
|
||||
/* -1 timeout means just do forced service */
|
||||
_lws_plat_service_tsi(context, -1, pt->tid);
|
||||
/* still somebody left who wants forced service? */
|
||||
if (!lws_service_adjust_timeout(context, 1, pt->tid))
|
||||
/* yes... come back again quickly */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
|
||||
if (timeout_ms) {
|
||||
lws_pt_lock(pt, __func__);
|
||||
/* don't stay in poll wait longer than next hr timeout */
|
||||
lws_usec_t t = __lws_hrtimer_service(pt);
|
||||
if ((lws_usec_t)timeout_ms * 1000 > t)
|
||||
timeout_ms = t / 1000;
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
vpt->inside_poll = 1;
|
||||
lws_memory_barrier();
|
||||
n = poll(pt->fds, pt->fds_count, timeout_ms);
|
||||
vpt->inside_poll = 0;
|
||||
lws_memory_barrier();
|
||||
|
||||
/* Collision will be rare and brief. Just spin until it completes */
|
||||
while (vpt->foreign_spinlock)
|
||||
;
|
||||
|
||||
/*
|
||||
* At this point we are not inside a foreign thread pollfd change,
|
||||
* and we have marked ourselves as outside the poll() wait. So we
|
||||
* are the only guys that can modify the lws_foreign_thread_pollfd
|
||||
* list on the pt. Drain the list and apply the changes to the
|
||||
* affected pollfds in the correct order.
|
||||
*/
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
ftp = vpt->foreign_pfd_list;
|
||||
//lwsl_notice("cleared list %p\n", ftp);
|
||||
while (ftp) {
|
||||
struct lws *wsi;
|
||||
struct lws_pollfd *pfd;
|
||||
|
||||
next = ftp->next;
|
||||
pfd = &vpt->fds[ftp->fd_index];
|
||||
if (lws_socket_is_valid(pfd->fd)) {
|
||||
wsi = wsi_from_fd(context, pfd->fd);
|
||||
if (wsi)
|
||||
__lws_change_pollfd(wsi, ftp->_and, ftp->_or);
|
||||
}
|
||||
lws_free((void *)ftp);
|
||||
ftp = next;
|
||||
}
|
||||
vpt->foreign_pfd_list = NULL;
|
||||
lws_memory_barrier();
|
||||
|
||||
/* we have come out of a poll wait... check the hrtimer list */
|
||||
|
||||
__lws_hrtimer_service(pt);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
m = 0;
|
||||
#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
m |= !!pt->ws.rx_draining_ext_list;
|
||||
#endif
|
||||
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
|
||||
|
||||
if (!m && !n) { /* nothing to do */
|
||||
lws_service_fd_tsi(context, NULL, tsi);
|
||||
lws_service_do_ripe_rxflow(pt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
faked_service:
|
||||
m = lws_service_flag_pending(context, tsi);
|
||||
if (m)
|
||||
c = -1; /* unknown limit */
|
||||
else
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO != LWS_EINTR)
|
||||
return -1;
|
||||
return 0;
|
||||
} else
|
||||
c = n;
|
||||
|
||||
/* any socket with events to service? */
|
||||
for (n = 0; n < (int)pt->fds_count && c; n++) {
|
||||
if (!pt->fds[n].revents)
|
||||
continue;
|
||||
|
||||
c--;
|
||||
|
||||
m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
/* if something closed, retry this slot */
|
||||
if (m)
|
||||
n--;
|
||||
}
|
||||
|
||||
lws_service_do_ripe_rxflow(pt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_check_connection_error(struct lws *wsi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
return _lws_plat_service_tsi(context, timeout_ms, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
||||
{
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
|
||||
#ifdef LWS_WITH_IPV6
|
||||
optval = 0;
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&optval, optlen);
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__HAIKU__)
|
||||
struct protoent *tcp_proto;
|
||||
#endif
|
||||
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
if (vhost->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(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \
|
||||
defined(__HAIKU__)
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
#if defined(LWS_HAVE_TCP_USER_TIMEOUT)
|
||||
optval = 1000 * (vhost->ka_time +
|
||||
(vhost->ka_interval * vhost->ka_probes));
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#endif
|
||||
optval = vhost->ka_time;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
optval = vhost->ka_interval;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
optval = vhost->ka_probes;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (vhost->bind_iface && vhost->iface) {
|
||||
lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
|
||||
strlen(vhost->iface)) < 0) {
|
||||
lwsl_warn("Failed to bind to device %s\n", vhost->iface);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
#if defined (__sun) || defined(__QNX__)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#elif !defined(__APPLE__) && \
|
||||
!defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \
|
||||
!defined(__NetBSD__) && \
|
||||
!defined(__OpenBSD__) && \
|
||||
!defined(__HAIKU__)
|
||||
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;
|
||||
}
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
static void
|
||||
_lws_plat_apply_caps(int mode, const cap_value_t *cv, int count)
|
||||
{
|
||||
cap_t caps;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
caps = cap_get_proc();
|
||||
|
||||
cap_set_flag(caps, mode, count, cv, CAP_SET);
|
||||
cap_set_proc(caps);
|
||||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
|
||||
cap_free(caps);
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_drop_app_privileges(const struct lws_context_creation_info *info)
|
||||
{
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
int n;
|
||||
#endif
|
||||
|
||||
if (info->gid && info->gid != -1)
|
||||
if (setgid(info->gid))
|
||||
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
|
||||
|
||||
if (info->uid && info->uid != -1) {
|
||||
struct passwd *p = getpwuid(info->uid);
|
||||
|
||||
if (p) {
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
_lws_plat_apply_caps(CAP_PERMITTED, info->caps, info->count_caps);
|
||||
#endif
|
||||
|
||||
initgroups(p->pw_name, info->gid);
|
||||
if (setuid(info->uid))
|
||||
lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
|
||||
else
|
||||
lwsl_notice("Set privs to user '%s'\n", p->pw_name);
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
_lws_plat_apply_caps(CAP_EFFECTIVE, info->caps, info->count_caps);
|
||||
|
||||
if (info->count_caps)
|
||||
for (n = 0; n < info->count_caps; n++)
|
||||
lwsl_notice(" RETAINING CAPABILITY %d\n", (int)info->caps[n]);
|
||||
#endif
|
||||
|
||||
} else
|
||||
lwsl_warn("getpwuid: unable to find uid %d", info->uid);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
|
||||
#if defined(LWS_WITH_LIBUV) && UV_VERSION_MAJOR > 0
|
||||
|
||||
/* libuv.c implements these in a cross-platform way */
|
||||
|
||||
#else
|
||||
|
||||
static int filter(const struct dirent *ent)
|
||||
{
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_plugins_init(struct lws_context * context, const char * const *d)
|
||||
{
|
||||
struct lws_plugin_capability lcaps;
|
||||
struct lws_plugin *plugin;
|
||||
lws_plugin_init_func initfunc;
|
||||
struct dirent **namelist;
|
||||
int n, i, m, ret = 0;
|
||||
char path[256];
|
||||
void *l;
|
||||
|
||||
lwsl_notice(" Plugins:\n");
|
||||
|
||||
while (d && *d) {
|
||||
n = scandir(*d, &namelist, filter, alphasort);
|
||||
if (n < 0) {
|
||||
lwsl_err("Scandir on %s failed\n", *d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strlen(namelist[i]->d_name) < 7)
|
||||
goto inval;
|
||||
|
||||
lwsl_notice(" %s\n", namelist[i]->d_name);
|
||||
|
||||
lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
|
||||
namelist[i]->d_name);
|
||||
l = dlopen(path, RTLD_NOW);
|
||||
if (!l) {
|
||||
lwsl_err("Error loading DSO: %s\n", dlerror());
|
||||
while (i++ < n)
|
||||
free(namelist[i]);
|
||||
goto bail;
|
||||
}
|
||||
/* we could open it, can we get his init function? */
|
||||
m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
|
||||
namelist[i]->d_name + 3 /* snip lib... */);
|
||||
path[m - 3] = '\0'; /* snip the .so */
|
||||
initfunc = dlsym(l, path);
|
||||
if (!initfunc) {
|
||||
lwsl_err("Failed to get init on %s: %s",
|
||||
namelist[i]->d_name, dlerror());
|
||||
dlclose(l);
|
||||
}
|
||||
lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
|
||||
m = initfunc(context, &lcaps);
|
||||
if (m) {
|
||||
lwsl_err("Initializing %s failed %d\n",
|
||||
namelist[i]->d_name, m);
|
||||
dlclose(l);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
plugin = lws_malloc(sizeof(*plugin), "plugin");
|
||||
if (!plugin) {
|
||||
lwsl_err("OOM\n");
|
||||
goto bail;
|
||||
}
|
||||
plugin->list = context->plugin_list;
|
||||
context->plugin_list = plugin;
|
||||
lws_strncpy(plugin->name, namelist[i]->d_name,
|
||||
sizeof(plugin->name));
|
||||
plugin->l = l;
|
||||
plugin->caps = lcaps;
|
||||
context->plugin_protocol_count += lcaps.count_protocols;
|
||||
context->plugin_extension_count += lcaps.count_extensions;
|
||||
|
||||
free(namelist[i]);
|
||||
continue;
|
||||
|
||||
skip:
|
||||
dlclose(l);
|
||||
inval:
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
d++;
|
||||
}
|
||||
|
||||
bail:
|
||||
free(namelist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_plugins_destroy(struct lws_context * context)
|
||||
{
|
||||
struct lws_plugin *plugin = context->plugin_list, *p;
|
||||
lws_plugin_destroy_func func;
|
||||
char path[256];
|
||||
int m;
|
||||
|
||||
if (!plugin)
|
||||
return 0;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
while (plugin) {
|
||||
p = plugin;
|
||||
m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
|
||||
path[m - 3] = '\0';
|
||||
func = dlsym(plugin->l, path);
|
||||
if (!func) {
|
||||
lwsl_err("Failed to get destroy on %s: %s",
|
||||
plugin->name, dlerror());
|
||||
goto next;
|
||||
}
|
||||
m = func(context);
|
||||
if (m)
|
||||
lwsl_err("Initializing %s failed %d\n",
|
||||
plugin->name, m);
|
||||
next:
|
||||
dlclose(p->l);
|
||||
plugin = p->list;
|
||||
p->list = NULL;
|
||||
free(p);
|
||||
}
|
||||
|
||||
context->plugin_list = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
sigabrt_handler(int x)
|
||||
{
|
||||
printf("%s\n", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
#if !defined(LWS_AVOID_SIGPIPE_IGN)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_early_destroy(struct lws_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_late_destroy(struct lws_context *context)
|
||||
{
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_list)
|
||||
lws_plat_plugins_destroy(context);
|
||||
#endif
|
||||
|
||||
if (context->lws_lookup)
|
||||
lws_free(context->lws_lookup);
|
||||
|
||||
if (!context->fd_random)
|
||||
lwsl_err("ZERO RANDOM FD\n");
|
||||
if (context->fd_random != LWS_INVALID_FILE)
|
||||
close(context->fd_random);
|
||||
}
|
||||
|
||||
/* cast a struct sockaddr_in6 * into addr for ipv6 */
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
|
||||
size_t addrlen)
|
||||
{
|
||||
int rc = LWS_ITOSA_NOT_EXIST;
|
||||
|
||||
struct ifaddrs *ifr;
|
||||
struct ifaddrs *ifc;
|
||||
#ifdef LWS_WITH_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_debug(" interface %s vs %s (fam %d) ipv6 %d\n", ifc->ifa_name, ifname, ifc->ifa_addr->sa_family, ipv6);
|
||||
|
||||
if (strcmp(ifc->ifa_name, ifname))
|
||||
continue;
|
||||
|
||||
switch (ifc->ifa_addr->sa_family) {
|
||||
#if defined(AF_PACKET)
|
||||
case AF_PACKET:
|
||||
/* interface exists but is not usable */
|
||||
rc = LWS_ITOSA_NOT_USABLE;
|
||||
continue;
|
||||
#endif
|
||||
|
||||
case AF_INET:
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (ipv6) {
|
||||
/* 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_WITH_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 = LWS_ITOSA_USABLE;
|
||||
}
|
||||
|
||||
freeifaddrs(ifr);
|
||||
|
||||
if (rc) {
|
||||
/* check if bind to IP address */
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
|
||||
rc = LWS_ITOSA_USABLE;
|
||||
else
|
||||
#endif
|
||||
if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
|
||||
rc = LWS_ITOSA_USABLE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
if (context->event_loop_ops->io)
|
||||
context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
||||
struct lws *wsi, int m)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
if (context->event_loop_ops->io)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
|
||||
pt->fds_count--;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_service_periodic(struct lws_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 lws_context *context,
|
||||
struct lws *wsi, struct lws_pollfd *pfd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
return inet_pton(af, src, dst);
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fop_fd_t
|
||||
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
const char *vpath, lws_fop_flags_t *flags)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int ret = open(filename, (*flags) & LWS_FOP_FLAGS_MASK, 0664);
|
||||
lws_fop_fd_t fop_fd;
|
||||
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
if (fstat(ret, &stat_buf) < 0)
|
||||
goto bail;
|
||||
|
||||
fop_fd = malloc(sizeof(*fop_fd));
|
||||
if (!fop_fd)
|
||||
goto bail;
|
||||
|
||||
fop_fd->fops = fops;
|
||||
fop_fd->flags = *flags;
|
||||
fop_fd->fd = ret;
|
||||
fop_fd->filesystem_priv = NULL; /* we don't use it */
|
||||
fop_fd->len = stat_buf.st_size;
|
||||
fop_fd->pos = 0;
|
||||
|
||||
return fop_fd;
|
||||
|
||||
bail:
|
||||
close(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
_lws_plat_file_close(lws_fop_fd_t *fop_fd)
|
||||
{
|
||||
int fd = (*fop_fd)->fd;
|
||||
|
||||
free(*fop_fd);
|
||||
*fop_fd = NULL;
|
||||
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fileofs_t
|
||||
_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
|
||||
{
|
||||
lws_fileofs_t r;
|
||||
|
||||
if (offset > 0 &&
|
||||
offset > (lws_fileofs_t)fop_fd->len - (lws_fileofs_t)fop_fd->pos)
|
||||
offset = fop_fd->len - fop_fd->pos;
|
||||
|
||||
if ((lws_fileofs_t)fop_fd->pos + offset < 0)
|
||||
offset = -fop_fd->pos;
|
||||
|
||||
r = lseek(fop_fd->fd, offset, SEEK_CUR);
|
||||
|
||||
if (r >= 0)
|
||||
fop_fd->pos = r;
|
||||
else
|
||||
lwsl_err("error seeking from cur %ld, offset %ld\n",
|
||||
(long)fop_fd->pos, (long)offset);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t *buf, lws_filepos_t len)
|
||||
{
|
||||
long n;
|
||||
|
||||
n = read((int)fop_fd->fd, buf, len);
|
||||
if (n == -1) {
|
||||
*amount = 0;
|
||||
return -1;
|
||||
}
|
||||
fop_fd->pos += n;
|
||||
lwsl_debug("%s: read %ld of req %ld, pos %ld, len %ld\n", __func__, n,
|
||||
(long)len, (long)fop_fd->pos, (long)fop_fd->len);
|
||||
*amount = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t *buf, lws_filepos_t len)
|
||||
{
|
||||
long n;
|
||||
|
||||
n = write((int)fop_fd->fd, buf, len);
|
||||
if (n == -1) {
|
||||
*amount = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fop_fd->pos += n;
|
||||
*amount = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* master context has the global fd lookup array */
|
||||
context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
|
||||
context->max_fds, "lws_lookup");
|
||||
if (context->lws_lookup == NULL) {
|
||||
lwsl_err("OOM on lws_lookup array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_info(" mem: platform fd map: %5lu bytes\n",
|
||||
(unsigned long)(sizeof(struct lws *) * context->max_fds));
|
||||
fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
|
||||
|
||||
context->fd_random = fd;
|
||||
if (context->fd_random < 0) {
|
||||
lwsl_err("Unable to open random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, context->fd_random);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (info->plugin_dirs)
|
||||
lws_plat_plugins_init(context, info->plugin_dirs);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
|
||||
int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = write(fd, buf, len);
|
||||
|
||||
fsync(fd);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
return n != len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_write_file(const char *filename, void *buf, int len)
|
||||
{
|
||||
int m, fd;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
|
||||
if (fd == -1)
|
||||
return 1;
|
||||
|
||||
m = write(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return m != len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_read_file(const char *filename, void *buf, int len)
|
||||
{
|
||||
int n, fd = lws_open(filename, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
n = read(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_recommended_rsa_bits(void)
|
||||
{
|
||||
return 4096;
|
||||
}
|
|
@ -1,852 +0,0 @@
|
|||
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#endif
|
||||
#include "core/private.h"
|
||||
|
||||
void lws_plat_apply_FD_CLOEXEC(int n)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_socket_offset(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_create(struct lws *wsi)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_signal(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
WSASetEvent(pt->events[0]); /* trigger the cancel event */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_pipe_close(struct lws *wsi)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
time_in_microseconds()
|
||||
{
|
||||
#ifndef DELTA_EPOCH_IN_MICROSECS
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
||||
#endif
|
||||
FILETIME filetime;
|
||||
ULARGE_INTEGER datetime;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
GetCurrentFT(&filetime);
|
||||
#else
|
||||
GetSystemTimeAsFileTime(&filetime);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* As per Windows documentation for FILETIME, copy the resulting
|
||||
* FILETIME structure to a ULARGE_INTEGER structure using memcpy
|
||||
* (using memcpy instead of direct assignment can prevent alignment
|
||||
* faults on 64-bit Windows).
|
||||
*/
|
||||
memcpy(&datetime, &filetime, sizeof(datetime));
|
||||
|
||||
/* Windows file times are in 100s of nanoseconds. */
|
||||
return (datetime.QuadPart / 10) - DELTA_EPOCH_IN_MICROSECS;
|
||||
}
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
time_t time(time_t *t)
|
||||
{
|
||||
time_t ret = time_in_microseconds() / 1000000;
|
||||
|
||||
if(t != NULL)
|
||||
*t = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* file descriptor hash management */
|
||||
|
||||
struct lws *
|
||||
wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
|
||||
{
|
||||
int h = LWS_FD_HASH(fd);
|
||||
int n = 0;
|
||||
|
||||
for (n = 0; n < context->fd_hashtable[h].length; n++)
|
||||
if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd)
|
||||
return context->fd_hashtable[h].wsi[n];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
insert_wsi(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
int h = LWS_FD_HASH(wsi->desc.sockfd);
|
||||
|
||||
if (context->fd_hashtable[h].length == (getdtablesize() - 1)) {
|
||||
lwsl_err("hash table overflow\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
|
||||
{
|
||||
int h = LWS_FD_HASH(fd);
|
||||
int n = 0;
|
||||
|
||||
for (n = 0; n < context->fd_hashtable[h].length; n++)
|
||||
if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd) {
|
||||
while (n < context->fd_hashtable[h].length) {
|
||||
context->fd_hashtable[h].wsi[n] =
|
||||
context->fd_hashtable[h].wsi[n + 1];
|
||||
n++;
|
||||
}
|
||||
context->fd_hashtable[h].length--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_err("Failed to find fd %d requested for "
|
||||
"delete in hashtable\n", fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_get_random(struct lws_context *context, void *buf, int len)
|
||||
{
|
||||
int n;
|
||||
char *p = (char *)buf;
|
||||
|
||||
for (n = 0; n < len; n++)
|
||||
p[n] = (unsigned char)rand();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_send_pipe_choked(struct lws *wsi)
|
||||
{ struct lws *wsi_eff = wsi;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
wsi_eff = lws_get_network_wsi(wsi);
|
||||
#endif
|
||||
/* the fact we checked implies we avoided back-to-back writes */
|
||||
wsi_eff->could_have_pending = 0;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (wsi_eff->trunc_len)
|
||||
return 1;
|
||||
|
||||
return (int)wsi_eff->sock_send_blocking;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_poll_listen_fd(struct lws_pollfd *fd)
|
||||
{
|
||||
fd_set readfds;
|
||||
struct timeval tv = { 0, 0 };
|
||||
|
||||
assert((fd->events & LWS_POLLIN) == LWS_POLLIN);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(fd->fd, &readfds);
|
||||
|
||||
return select(((int)fd->fd) + 1, &readfds, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lwsl_emit_syslog(int level, const char *line)
|
||||
{
|
||||
lwsl_emit_stderr(level, line);
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
WSANETWORKEVENTS networkevents;
|
||||
struct lws_pollfd *pfd;
|
||||
struct lws *wsi;
|
||||
unsigned int i;
|
||||
DWORD ev;
|
||||
int n, m;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
if (context == NULL || !context->vhost_list)
|
||||
return 1;
|
||||
|
||||
pt = &context->pt[tsi];
|
||||
|
||||
if (!context->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
||||
memset(&_lws, 0, sizeof(_lws));
|
||||
_lws.context = context;
|
||||
|
||||
context->service_tid_detected = context->vhost_list->
|
||||
protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
|
||||
NULL, NULL, 0);
|
||||
context->service_tid = context->service_tid_detected;
|
||||
context->service_tid_detected = 1;
|
||||
}
|
||||
|
||||
if (timeout_ms < 0) {
|
||||
if (lws_service_flag_pending(context, tsi)) {
|
||||
/* any socket with events to service? */
|
||||
for (n = 0; n < (int)pt->fds_count; n++) {
|
||||
if (!pt->fds[n].revents)
|
||||
continue;
|
||||
|
||||
m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
/* if something closed, retry this slot */
|
||||
if (m)
|
||||
n--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (context->event_loop_ops->run_pt)
|
||||
context->event_loop_ops->run_pt(context, tsi);
|
||||
|
||||
for (i = 0; i < pt->fds_count; ++i) {
|
||||
pfd = &pt->fds[i];
|
||||
|
||||
if (!(pfd->events & LWS_POLLOUT))
|
||||
continue;
|
||||
|
||||
wsi = wsi_from_fd(context, pfd->fd);
|
||||
if (!wsi || wsi->listener)
|
||||
continue;
|
||||
if (wsi->sock_send_blocking)
|
||||
continue;
|
||||
pfd->revents = LWS_POLLOUT;
|
||||
n = lws_service_fd(context, pfd);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
/* Force WSAWaitForMultipleEvents() to check events and then return immediately. */
|
||||
timeout_ms = 0;
|
||||
|
||||
/* if something closed, retry this slot */
|
||||
if (n)
|
||||
i--;
|
||||
}
|
||||
|
||||
/*
|
||||
* is there anybody with pending stuff that needs service forcing?
|
||||
*/
|
||||
if (!lws_service_adjust_timeout(context, 1, tsi)) {
|
||||
/* -1 timeout means just do forced service */
|
||||
_lws_plat_service_tsi(context, -1, pt->tid);
|
||||
/* still somebody left who wants forced service? */
|
||||
if (!lws_service_adjust_timeout(context, 1, pt->tid))
|
||||
/* yes... come back again quickly */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
|
||||
if (timeout_ms) {
|
||||
lws_usec_t t;
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
/* don't stay in poll wait longer than next hr timeout */
|
||||
t = __lws_hrtimer_service(pt);
|
||||
|
||||
if ((lws_usec_t)timeout_ms * 1000 > t)
|
||||
timeout_ms = (int)(t / 1000);
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
ev = WSAWaitForMultipleEvents(1, pt->events, FALSE, timeout_ms, FALSE);
|
||||
if (ev == WSA_WAIT_EVENT_0) {
|
||||
unsigned int eIdx, err;
|
||||
|
||||
WSAResetEvent(pt->events[0]);
|
||||
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
|
||||
|
||||
for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
|
||||
if (WSAEnumNetworkEvents(pt->fds[eIdx].fd, 0,
|
||||
&networkevents) == SOCKET_ERROR) {
|
||||
lwsl_err("WSAEnumNetworkEvents() failed "
|
||||
"with error %d\n", LWS_ERRNO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pfd = &pt->fds[eIdx];
|
||||
pfd->revents = (short)networkevents.lNetworkEvents;
|
||||
|
||||
err = networkevents.iErrorCode[FD_CONNECT_BIT];
|
||||
|
||||
if ((networkevents.lNetworkEvents & FD_CONNECT) &&
|
||||
err && err != LWS_EALREADY &&
|
||||
err != LWS_EINPROGRESS && err != LWS_EWOULDBLOCK &&
|
||||
err != WSAEINVAL) {
|
||||
lwsl_debug("Unable to connect errno=%d\n", err);
|
||||
pfd->revents |= LWS_POLLHUP;
|
||||
}
|
||||
|
||||
if (pfd->revents & LWS_POLLOUT) {
|
||||
wsi = wsi_from_fd(context, pfd->fd);
|
||||
if (wsi)
|
||||
wsi->sock_send_blocking = 0;
|
||||
}
|
||||
/* if something closed, retry this slot */
|
||||
if (pfd->revents & LWS_POLLHUP)
|
||||
--eIdx;
|
||||
|
||||
if (pfd->revents) {
|
||||
recv(pfd->fd, NULL, 0, 0);
|
||||
lws_service_fd_tsi(context, pfd, tsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context->service_tid = 0;
|
||||
|
||||
if (ev == WSA_WAIT_TIMEOUT)
|
||||
lws_service_fd(context, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
return _lws_plat_service_tsi(context, timeout_ms, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
|
||||
{
|
||||
int optval = 1;
|
||||
int optlen = sizeof(optval);
|
||||
u_long optl = 1;
|
||||
DWORD dwBytesRet;
|
||||
struct tcp_keepalive alive;
|
||||
int protonbr;
|
||||
#ifndef _WIN32_WCE
|
||||
struct protoent *tcp_proto;
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_IPV6
|
||||
optval = 0;
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&optval, optlen);
|
||||
#endif
|
||||
|
||||
if (vhost->ka_time) {
|
||||
/* enable keepalive on this socket */
|
||||
optval = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(const char *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
alive.onoff = TRUE;
|
||||
alive.keepalivetime = vhost->ka_time;
|
||||
alive.keepaliveinterval = vhost->ka_interval;
|
||||
|
||||
if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
|
||||
NULL, 0, &dwBytesRet, NULL, NULL))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
#ifndef _WIN32_WCE
|
||||
tcp_proto = getprotobyname("TCP");
|
||||
if (!tcp_proto) {
|
||||
lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO);
|
||||
return 1;
|
||||
}
|
||||
protonbr = tcp_proto->p_proto;
|
||||
#else
|
||||
protonbr = 6;
|
||||
#endif
|
||||
|
||||
setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen);
|
||||
|
||||
/* We are nonblocking... */
|
||||
ioctlsocket(fd, FIONBIO, &optl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_drop_app_privileges(const struct lws_context_creation_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
|
||||
/* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
|
||||
wVersionRequested = MAKEWORD(2, 2);
|
||||
|
||||
err = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (!err)
|
||||
return 0;
|
||||
/*
|
||||
* Tell the user that we could not find a usable
|
||||
* Winsock DLL
|
||||
*/
|
||||
lwsl_err("WSAStartup failed with error: %d\n", err);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_early_destroy(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int n = context->count_threads;
|
||||
|
||||
while (n--) {
|
||||
if (pt->events) {
|
||||
WSACloseEvent(pt->events[0]);
|
||||
lws_free(pt->events);
|
||||
}
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_late_destroy(struct lws_context *context)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
|
||||
if (context->fd_hashtable[n].wsi)
|
||||
lws_free(context->fd_hashtable[n].wsi);
|
||||
}
|
||||
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_interface_to_sa(int ipv6,
|
||||
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
|
||||
{
|
||||
#ifdef LWS_WITH_IPV6
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
||||
|
||||
if (ipv6) {
|
||||
if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) {
|
||||
return LWS_ITOSA_USABLE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
long long address = inet_addr(ifname);
|
||||
|
||||
if (address == INADDR_NONE) {
|
||||
struct hostent *entry = gethostbyname(ifname);
|
||||
if (entry)
|
||||
address = ((struct in_addr *)entry->h_addr_list[0])->s_addr;
|
||||
}
|
||||
|
||||
if (address == INADDR_NONE)
|
||||
return LWS_ITOSA_NOT_EXIST;
|
||||
|
||||
addr->sin_addr.s_addr = (unsigned long)(lws_intptr_t)address;
|
||||
|
||||
return LWS_ITOSA_USABLE;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
pt->events[pt->fds_count] = pt->events[0];
|
||||
WSAEventSelect(wsi->desc.sockfd, pt->events[0],
|
||||
LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
||||
struct lws *wsi, int m)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
pt->events[m + 1] = pt->events[pt->fds_count--];
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_service_periodic(struct lws_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_check_connection_error(struct lws *wsi)
|
||||
{
|
||||
int optVal;
|
||||
int optLen = sizeof(int);
|
||||
|
||||
if (getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR,
|
||||
(char*)&optVal, &optLen) != SOCKET_ERROR && optVal &&
|
||||
optVal != LWS_EALREADY && optVal != LWS_EINPROGRESS &&
|
||||
optVal != LWS_EWOULDBLOCK && optVal != WSAEINVAL) {
|
||||
lwsl_debug("Connect failed SO_ERROR=%d\n", optVal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_change_pollfd(struct lws_context *context,
|
||||
struct lws *wsi, struct lws_pollfd *pfd)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
long networkevents = LWS_POLLHUP | FD_CONNECT;
|
||||
|
||||
if ((pfd->events & LWS_POLLIN))
|
||||
networkevents |= LWS_POLLIN;
|
||||
|
||||
if ((pfd->events & LWS_POLLOUT))
|
||||
networkevents |= LWS_POLLOUT;
|
||||
|
||||
if (WSAEventSelect(wsi->desc.sockfd,
|
||||
pt->events[0],
|
||||
networkevents) != SOCKET_ERROR)
|
||||
return 0;
|
||||
|
||||
lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
WCHAR *buffer;
|
||||
DWORD bufferlen = cnt;
|
||||
BOOL ok = FALSE;
|
||||
|
||||
buffer = lws_malloc(bufferlen * 2, "inet_ntop");
|
||||
if (!buffer) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in srcaddr;
|
||||
bzero(&srcaddr, sizeof(srcaddr));
|
||||
srcaddr.sin_family = AF_INET;
|
||||
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
|
||||
|
||||
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
|
||||
ok = TRUE;
|
||||
#ifdef LWS_WITH_IPV6
|
||||
} else if (af == AF_INET6) {
|
||||
struct sockaddr_in6 srcaddr;
|
||||
bzero(&srcaddr, sizeof(srcaddr));
|
||||
srcaddr.sin6_family = AF_INET6;
|
||||
memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
|
||||
|
||||
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
|
||||
ok = TRUE;
|
||||
#endif
|
||||
} else
|
||||
lwsl_err("Unsupported type\n");
|
||||
|
||||
if (!ok) {
|
||||
int rv = WSAGetLastError();
|
||||
lwsl_err("WSAAddressToString() : %d\n", rv);
|
||||
} else {
|
||||
if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
|
||||
ok = FALSE;
|
||||
}
|
||||
|
||||
lws_free(buffer);
|
||||
return ok ? dst : NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
WCHAR *buffer;
|
||||
DWORD bufferlen = (int)strlen(src) + 1;
|
||||
BOOL ok = FALSE;
|
||||
|
||||
buffer = lws_malloc(bufferlen * 2, "inet_pton");
|
||||
if (!buffer) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) {
|
||||
lwsl_err("Failed to convert multi byte to wide char\n");
|
||||
lws_free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in dstaddr;
|
||||
int dstaddrlen = sizeof(dstaddr);
|
||||
bzero(&dstaddr, sizeof(dstaddr));
|
||||
dstaddr.sin_family = AF_INET;
|
||||
|
||||
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
|
||||
ok = TRUE;
|
||||
memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr));
|
||||
}
|
||||
#ifdef LWS_WITH_IPV6
|
||||
} else if (af == AF_INET6) {
|
||||
struct sockaddr_in6 dstaddr;
|
||||
int dstaddrlen = sizeof(dstaddr);
|
||||
bzero(&dstaddr, sizeof(dstaddr));
|
||||
dstaddr.sin6_family = AF_INET6;
|
||||
|
||||
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
|
||||
ok = TRUE;
|
||||
memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
lwsl_err("Unsupported type\n");
|
||||
|
||||
if (!ok) {
|
||||
int rv = WSAGetLastError();
|
||||
lwsl_err("WSAAddressToString() : %d\n", rv);
|
||||
}
|
||||
|
||||
lws_free(buffer);
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fop_fd_t
|
||||
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
const char *vpath, lws_fop_flags_t *flags)
|
||||
{
|
||||
HANDLE ret;
|
||||
WCHAR buf[MAX_PATH];
|
||||
lws_fop_fd_t fop_fd;
|
||||
FILE_STANDARD_INFO fInfo = {0};
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, LWS_ARRAY_SIZE(buf));
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 // Windows 8 (minimum when UWP_ENABLED, but can be used in Windows builds)
|
||||
CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
|
||||
extParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
if (((*flags) & 7) == _O_RDONLY) {
|
||||
ret = CreateFile2(buf, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extParams);
|
||||
} else {
|
||||
ret = CreateFile2(buf, GENERIC_WRITE, 0, CREATE_ALWAYS, &extParams);
|
||||
}
|
||||
#else
|
||||
if (((*flags) & 7) == _O_RDONLY) {
|
||||
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
} else {
|
||||
ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret == LWS_INVALID_FILE)
|
||||
goto bail;
|
||||
|
||||
fop_fd = malloc(sizeof(*fop_fd));
|
||||
if (!fop_fd)
|
||||
goto bail;
|
||||
|
||||
fop_fd->fops = fops;
|
||||
fop_fd->fd = ret;
|
||||
fop_fd->filesystem_priv = NULL; /* we don't use it */
|
||||
fop_fd->flags = *flags;
|
||||
fop_fd->len = 0;
|
||||
if(GetFileInformationByHandleEx(ret, FileStandardInfo, &fInfo, sizeof(fInfo)))
|
||||
fop_fd->len = fInfo.EndOfFile.QuadPart;
|
||||
|
||||
fop_fd->pos = 0;
|
||||
|
||||
return fop_fd;
|
||||
|
||||
bail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
_lws_plat_file_close(lws_fop_fd_t *fop_fd)
|
||||
{
|
||||
HANDLE fd = (*fop_fd)->fd;
|
||||
|
||||
free(*fop_fd);
|
||||
*fop_fd = NULL;
|
||||
|
||||
CloseHandle((HANDLE)fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fileofs_t
|
||||
_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
|
||||
{
|
||||
LARGE_INTEGER l;
|
||||
|
||||
l.QuadPart = offset;
|
||||
return SetFilePointerEx((HANDLE)fop_fd->fd, l, NULL, FILE_CURRENT);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t *buf, lws_filepos_t len)
|
||||
{
|
||||
DWORD _amount;
|
||||
|
||||
if (!ReadFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
|
||||
*amount = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
fop_fd->pos += _amount;
|
||||
*amount = (unsigned long)_amount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t* buf, lws_filepos_t len)
|
||||
{
|
||||
DWORD _amount;
|
||||
|
||||
if (!WriteFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
|
||||
*amount = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
fop_fd->pos += _amount;
|
||||
*amount = (unsigned long)_amount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int i, n = context->count_threads;
|
||||
|
||||
for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
|
||||
context->fd_hashtable[i].wsi =
|
||||
lws_zalloc(sizeof(struct lws*) * context->max_fds, "win hashtable");
|
||||
|
||||
if (!context->fd_hashtable[i].wsi)
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
pt->events = lws_malloc(sizeof(WSAEVENT) *
|
||||
(context->fd_limit_per_thread + 1), "event table");
|
||||
if (pt->events == NULL) {
|
||||
lwsl_err("Unable to allocate events array for %d connections\n",
|
||||
context->fd_limit_per_thread + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pt->fds_count = 0;
|
||||
pt->events[0] = WSACreateEvent(); /* the cancel event */
|
||||
|
||||
pt++;
|
||||
}
|
||||
|
||||
context->fd_random = 0;
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (info->plugin_dirs)
|
||||
lws_plat_plugins_init(context, info->plugin_dirs);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int kill(int pid, int sig)
|
||||
{
|
||||
lwsl_err("Sorry Windows doesn't support kill().");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int fork(void)
|
||||
{
|
||||
lwsl_err("Sorry Windows doesn't support fork().");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
|
||||
int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = write(fd, buf, len);
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
return n != len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_write_file(const char *filename, void *buf, int len)
|
||||
{
|
||||
int m, fd;
|
||||
|
||||
fd = lws_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
m = write(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return m != len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_read_file(const char *filename, void *buf, int len)
|
||||
{
|
||||
int n, fd = lws_open(filename, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
n = read(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_recommended_rsa_bits(void)
|
||||
{
|
||||
return 4096;
|
||||
}
|
|
@ -1,701 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 <core/private.h>
|
||||
|
||||
#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.
|
||||
*
|
||||
* Returns <0 for error or length of chars consumed from buf (up to len)
|
||||
*/
|
||||
|
||||
int
|
||||
lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
||||
{
|
||||
unsigned char *last_char, *oldbuf = buf;
|
||||
lws_filepos_t body_chunk_len;
|
||||
size_t n;
|
||||
|
||||
// lwsl_notice("%s: h1 path: wsi state 0x%x\n", __func__, lwsi_state(wsi));
|
||||
|
||||
switch (lwsi_state(wsi)) {
|
||||
|
||||
case LRS_ISSUING_FILE:
|
||||
return 0;
|
||||
|
||||
case LRS_ESTABLISHED:
|
||||
|
||||
if (lwsi_role_ws(wsi))
|
||||
goto ws_mode;
|
||||
|
||||
if (lwsi_role_client(wsi))
|
||||
break;
|
||||
|
||||
wsi->hdr_parsing_completed = 0;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LRS_HEADERS:
|
||||
if (!wsi->http.ah) {
|
||||
lwsl_err("%s: LRS_HEADERS: NULL ah\n", __func__);
|
||||
assert(0);
|
||||
}
|
||||
lwsl_parser("issuing %d bytes to parser\n", (int)len);
|
||||
#if defined(LWS_ROLE_WS) && !defined(LWS_NO_CLIENT)
|
||||
if (lws_ws_handshake_client(wsi, &buf, (size_t)len))
|
||||
goto bail;
|
||||
#endif
|
||||
last_char = buf;
|
||||
if (lws_handshake_server(wsi, &buf, (size_t)len))
|
||||
/* Handshake indicates this session is done. */
|
||||
goto bail;
|
||||
|
||||
/* we might have transitioned to RAW */
|
||||
if (wsi->role_ops == &role_ops_raw_skt ||
|
||||
wsi->role_ops == &role_ops_raw_file)
|
||||
/* we gave the read buffer to RAW handler already */
|
||||
goto read_ok;
|
||||
|
||||
/*
|
||||
* It's possible that we've exhausted our data already, or
|
||||
* rx flow control has stopped us dealing with this early,
|
||||
* 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);
|
||||
// lwsl_debug("%s: thinks we have used %ld\n", __func__, (long)len);
|
||||
|
||||
if (!wsi->hdr_parsing_completed)
|
||||
/* More header content on the way */
|
||||
goto read_ok;
|
||||
|
||||
switch (lwsi_state(wsi)) {
|
||||
case LRS_ESTABLISHED:
|
||||
case LRS_HEADERS:
|
||||
goto read_ok;
|
||||
case LRS_ISSUING_FILE:
|
||||
goto read_ok;
|
||||
case LRS_BODY:
|
||||
wsi->http.rx_content_remain =
|
||||
wsi->http.rx_content_length;
|
||||
if (wsi->http.rx_content_remain)
|
||||
goto http_postbody;
|
||||
|
||||
/* there is no POST content */
|
||||
goto postbody_completion;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LRS_BODY:
|
||||
http_postbody:
|
||||
lwsl_debug("%s: http post body: remain %d\n", __func__,
|
||||
(int)wsi->http.rx_content_remain);
|
||||
while (len && wsi->http.rx_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->http.rx_content_remain, len);
|
||||
wsi->http.rx_content_remain -= body_chunk_len;
|
||||
len -= body_chunk_len;
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->http.cgi) {
|
||||
struct lws_cgi_args args;
|
||||
|
||||
args.ch = LWS_STDIN;
|
||||
args.stdwsi = &wsi->http.cgi->stdwsi[0];
|
||||
args.data = buf;
|
||||
args.len = body_chunk_len;
|
||||
|
||||
/* returns how much used */
|
||||
n = user_callback_handle_rxflow(
|
||||
wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_CGI_STDIN_DATA,
|
||||
wsi->user_space,
|
||||
(void *)&args, 0);
|
||||
if ((int)n < 0)
|
||||
goto bail;
|
||||
} else {
|
||||
#endif
|
||||
n = wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_HTTP_BODY, wsi->user_space,
|
||||
buf, (size_t)body_chunk_len);
|
||||
if (n)
|
||||
goto bail;
|
||||
n = (size_t)body_chunk_len;
|
||||
#ifdef LWS_WITH_CGI
|
||||
}
|
||||
#endif
|
||||
buf += n;
|
||||
|
||||
if (wsi->http.rx_content_remain) {
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
wsi->context->timeout_secs);
|
||||
break;
|
||||
}
|
||||
/* he sent all the content in time */
|
||||
postbody_completion:
|
||||
#ifdef LWS_WITH_CGI
|
||||
/*
|
||||
* If we're running a cgi, we can't let him off the
|
||||
* hook just because he sent his POST data
|
||||
*/
|
||||
if (wsi->http.cgi)
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI,
|
||||
wsi->context->timeout_secs);
|
||||
else
|
||||
#endif
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (!wsi->http.cgi)
|
||||
#endif
|
||||
{
|
||||
lwsl_info("HTTP_BODY_COMPLETION: %p (%s)\n",
|
||||
wsi, wsi->protocol->name);
|
||||
n = wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_HTTP_BODY_COMPLETION,
|
||||
wsi->user_space, NULL, 0);
|
||||
if (n)
|
||||
goto bail;
|
||||
|
||||
if (wsi->http2_substream)
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LRS_RETURNED_CLOSE:
|
||||
case LRS_AWAITING_CLOSE_ACK:
|
||||
case LRS_WAITING_TO_SEND_CLOSE:
|
||||
case LRS_SHUTDOWN:
|
||||
|
||||
ws_mode:
|
||||
#if !defined(LWS_NO_CLIENT) && defined(LWS_ROLE_WS)
|
||||
// lwsl_notice("%s: ws_mode\n", __func__);
|
||||
if (lws_ws_handshake_client(wsi, &buf, (size_t)len))
|
||||
goto bail;
|
||||
#endif
|
||||
#if defined(LWS_ROLE_WS)
|
||||
if (lwsi_role_ws(wsi) && lwsi_role_server(wsi) &&
|
||||
/*
|
||||
* for h2 we are on the swsi
|
||||
*/
|
||||
lws_parse_ws(wsi, &buf, (size_t)len) < 0) {
|
||||
lwsl_info("%s: lws_parse_ws bailed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
#endif
|
||||
// lwsl_notice("%s: ws_mode: buf moved on by %d\n", __func__,
|
||||
// lws_ptr_diff(buf, oldbuf));
|
||||
break;
|
||||
|
||||
case LRS_DEFERRING_ACTION:
|
||||
lwsl_debug("%s: LRS_DEFERRING_ACTION\n", __func__);
|
||||
break;
|
||||
|
||||
case LRS_SSL_ACK_PENDING:
|
||||
break;
|
||||
|
||||
case LRS_DEAD_SOCKET:
|
||||
lwsl_err("%s: Unhandled state LRS_DEAD_SOCKET\n", __func__);
|
||||
goto bail;
|
||||
// assert(0);
|
||||
/* fallthru */
|
||||
|
||||
default:
|
||||
lwsl_err("%s: Unhandled state %d\n", __func__, lwsi_state(wsi));
|
||||
assert(0);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
read_ok:
|
||||
/* Nothing more to do for now */
|
||||
// lwsl_info("%s: %p: read_ok, used %ld (len %d, state %d)\n", __func__,
|
||||
// wsi, (long)(buf - oldbuf), (int)len, wsi->state);
|
||||
|
||||
return lws_ptr_diff(buf, oldbuf);
|
||||
|
||||
bail:
|
||||
/*
|
||||
* h2 / h2-ws calls us recursively in
|
||||
*
|
||||
* lws_read_h1()->
|
||||
* lws_h2_parser()->
|
||||
* lws_read_h1()
|
||||
*
|
||||
* pattern, having stripped the h2 framing in the middle.
|
||||
*
|
||||
* When taking down the whole connection, make sure that only the
|
||||
* outer lws_read() does the wsi close.
|
||||
*/
|
||||
if (!wsi->outer_will_close)
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"lws_read_h1 bail");
|
||||
|
||||
return -1;
|
||||
}
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
static int
|
||||
lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct lws_tokens ebuf;
|
||||
int n, buffered;
|
||||
|
||||
if (lwsi_state(wsi) == LRS_DEFERRING_ACTION)
|
||||
goto try_pollout;
|
||||
|
||||
/* any incoming data ready? */
|
||||
|
||||
if (!(pollfd->revents & pollfd->events & LWS_POLLIN))
|
||||
goto try_pollout;
|
||||
|
||||
/*
|
||||
* If we previously just did POLLIN when IN and OUT were signaled
|
||||
* (because POLLIN processing may have used up the POLLOUT), don't let
|
||||
* that happen twice in a row... next time we see the situation favour
|
||||
* POLLOUT
|
||||
*/
|
||||
|
||||
if (wsi->favoured_pollin &&
|
||||
(pollfd->revents & pollfd->events & LWS_POLLOUT)) {
|
||||
// lwsl_notice("favouring pollout\n");
|
||||
wsi->favoured_pollin = 0;
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
/*
|
||||
* We haven't processed that the tunnel is set up yet, so
|
||||
* defer reading
|
||||
*/
|
||||
|
||||
if (lwsi_state(wsi) == LRS_SSL_ACK_PENDING)
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
/* these states imply we MUST have an ah attached */
|
||||
|
||||
if ((lwsi_state(wsi) == LRS_ESTABLISHED ||
|
||||
lwsi_state(wsi) == LRS_ISSUING_FILE ||
|
||||
lwsi_state(wsi) == LRS_HEADERS ||
|
||||
lwsi_state(wsi) == LRS_BODY)) {
|
||||
|
||||
if (!wsi->http.ah && lws_header_table_attach(wsi, 0)) {
|
||||
lwsl_info("%s: wsi %p: ah not available\n", __func__, wsi);
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
/*
|
||||
* We got here because there was specifically POLLIN...
|
||||
* regardless of our buflist state, we need to get it,
|
||||
* and either use it, or append to the buflist and use
|
||||
* buflist head material.
|
||||
*
|
||||
* We will not notice a connection close until the buflist is
|
||||
* exhausted and we tried to do a read of some kind.
|
||||
*/
|
||||
|
||||
buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
|
||||
switch (ebuf.len) {
|
||||
case 0:
|
||||
lwsl_info("%s: read 0 len a\n", __func__);
|
||||
wsi->seen_zero_length_recv = 1;
|
||||
lws_change_pollfd(wsi, LWS_POLLIN, 0);
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
/*
|
||||
* autobahn requires us to win the race between close
|
||||
* and draining the extensions
|
||||
*/
|
||||
if (wsi->ws &&
|
||||
(wsi->ws->rx_draining_ext || wsi->ws->tx_draining_ext))
|
||||
goto try_pollout;
|
||||
#endif
|
||||
/*
|
||||
* normally, we respond to close with logically closing
|
||||
* our side immediately
|
||||
*/
|
||||
goto fail;
|
||||
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto fail;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
/* just ignore incoming if waiting for close */
|
||||
if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
|
||||
lwsl_notice("%s: just ignoring\n", __func__);
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
if (lwsi_state(wsi) == LRS_ISSUING_FILE) {
|
||||
// lwsl_notice("stashing: wsi %p: bd %d\n", wsi, buffered);
|
||||
if (lws_buflist_aware_consume(wsi, &ebuf, 0, buffered))
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise give it to whoever wants it according to the
|
||||
* connection state
|
||||
*/
|
||||
#if defined(LWS_ROLE_H2)
|
||||
if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY)
|
||||
n = lws_read_h2(wsi, (uint8_t *)ebuf.token, ebuf.len);
|
||||
else
|
||||
#endif
|
||||
n = lws_read_h1(wsi, (uint8_t *)ebuf.token, ebuf.len);
|
||||
if (n < 0) /* we closed wsi */
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
|
||||
lwsl_debug("%s: consumed %d\n", __func__, n);
|
||||
|
||||
if (lws_buflist_aware_consume(wsi, &ebuf, n, buffered))
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
|
||||
/*
|
||||
* during the parsing our role changed to something non-http,
|
||||
* so the ah has no further meaning
|
||||
*/
|
||||
|
||||
if (wsi->http.ah &&
|
||||
!lwsi_role_h1(wsi) &&
|
||||
!lwsi_role_h2(wsi) &&
|
||||
!lwsi_role_cgi(wsi))
|
||||
lws_header_table_detach(wsi, 0);
|
||||
|
||||
/*
|
||||
* He may have used up the writability above, if we will defer
|
||||
* POLLOUT processing in favour of POLLIN, note it
|
||||
*/
|
||||
|
||||
if (pollfd->revents & LWS_POLLOUT)
|
||||
wsi->favoured_pollin = 1;
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* He may have used up the writability above, if we will defer POLLOUT
|
||||
* processing in favour of POLLIN, note it
|
||||
*/
|
||||
|
||||
if (pollfd->revents & LWS_POLLOUT)
|
||||
wsi->favoured_pollin = 1;
|
||||
|
||||
try_pollout:
|
||||
|
||||
/* this handles POLLOUT for http serving fragments */
|
||||
|
||||
if (!(pollfd->revents & LWS_POLLOUT))
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
/* one shot */
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_notice("%s a\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* clear back-to-back write detection */
|
||||
wsi->could_have_pending = 0;
|
||||
|
||||
if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) {
|
||||
lwsl_debug("%s: LRS_DEFERRING_ACTION now writable\n", __func__);
|
||||
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wsi->hdr_parsing_completed)
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
if (lwsi_state(wsi) != LRS_ISSUING_FILE) {
|
||||
|
||||
if (wsi->trunc_len) {
|
||||
//lwsl_notice("%s: completing partial\n", __func__);
|
||||
if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset,
|
||||
wsi->trunc_len) < 0) {
|
||||
lwsl_info("%s signalling to close\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_WRITEABLE_CB, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (wsi->active_writable_req_us) {
|
||||
uint64_t ul = time_in_microseconds() -
|
||||
wsi->active_writable_req_us;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_MS_WRITABLE_DELAY, ul);
|
||||
lws_stats_atomic_max(wsi->context, pt,
|
||||
LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
|
||||
wsi->active_writable_req_us = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
n = user_callback_handle_rxflow(wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_HTTP_WRITEABLE,
|
||||
wsi->user_space, NULL, 0);
|
||||
if (n < 0) {
|
||||
lwsl_info("writeable_fail\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
/* >0 == completion, <0 == error
|
||||
*
|
||||
* We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
|
||||
* it's done. That's the case even if we just completed the
|
||||
* send, so wait for that.
|
||||
*/
|
||||
n = lws_serve_http_file_fragment(wsi);
|
||||
if (n < 0)
|
||||
goto fail;
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
|
||||
fail:
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"server socket svc fail");
|
||||
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_pollfd *pollfd)
|
||||
{
|
||||
|
||||
// lwsl_notice("%s: %p: wsistate 0x%x %s, revents 0x%x\n", __func__, wsi,
|
||||
// wsi->wsistate, wsi->role_ops->name, pollfd->revents);
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->http.cgi && (pollfd->revents & LWS_POLLOUT)) {
|
||||
if (lws_handle_POLLOUT_event(wsi, pollfd))
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lws_is_flowcontrolled(wsi))
|
||||
/* We cannot deal with any kind of new RX because we are
|
||||
* RX-flowcontrolled.
|
||||
*/
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
if (!lwsi_role_client(wsi)) {
|
||||
int n;
|
||||
|
||||
lwsl_debug("%s: %p: wsistate 0x%x\n", __func__, wsi, wsi->wsistate);
|
||||
n = lws_h1_server_socket_service(wsi, pollfd);
|
||||
if (n != LWS_HPI_RET_HANDLED)
|
||||
return n;
|
||||
if (lwsi_state(wsi) != LRS_SSL_INIT)
|
||||
if (lws_server_socket_service_ssl(wsi, LWS_SOCK_INVALID))
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if ((pollfd->revents & LWS_POLLIN) &&
|
||||
wsi->hdr_parsing_completed && !wsi->told_user_closed) {
|
||||
|
||||
/*
|
||||
* In SSL mode we get POLLIN notification about
|
||||
* encrypted data in.
|
||||
*
|
||||
* But that is not necessarily related to decrypted
|
||||
* data out becoming available; in may need to perform
|
||||
* other in or out before that happens.
|
||||
*
|
||||
* simply mark ourselves as having readable data
|
||||
* and turn off our POLLIN
|
||||
*/
|
||||
wsi->client_rx_avail = 1;
|
||||
lws_change_pollfd(wsi, LWS_POLLIN, 0);
|
||||
|
||||
//lwsl_notice("calling back %s\n", wsi->protocol->name);
|
||||
|
||||
/* let user code know, he'll usually ask for writeable
|
||||
* callback and drain / re-enable it there
|
||||
*/
|
||||
if (user_callback_handle_rxflow(
|
||||
wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
||||
wsi->user_space, NULL, 0)) {
|
||||
lwsl_info("RECEIVE_CLIENT_HTTP closed it\n");
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
}
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
// if (lwsi_state(wsi) == LRS_ESTABLISHED)
|
||||
// return LWS_HPI_RET_HANDLED;
|
||||
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if ((pollfd->revents & LWS_POLLOUT) &&
|
||||
lws_handle_POLLOUT_event(wsi, pollfd)) {
|
||||
lwsl_debug("POLLOUT event closed it\n");
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
}
|
||||
|
||||
if (lws_client_socket_service(wsi, pollfd, NULL))
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
#endif
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
int rops_handle_POLLOUT_h1(struct lws *wsi)
|
||||
{
|
||||
if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY)
|
||||
return LWS_HP_RET_USER_SERVICE;
|
||||
|
||||
if (lwsi_role_client(wsi))
|
||||
return LWS_HP_RET_USER_SERVICE;
|
||||
|
||||
return LWS_HP_RET_BAIL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len,
|
||||
enum lws_write_protocol *wp)
|
||||
{
|
||||
#if 0
|
||||
/* if not in a state to send stuff, then just send nothing */
|
||||
|
||||
if ((lwsi_state(wsi) != LRS_RETURNED_CLOSE &&
|
||||
lwsi_state(wsi) != LRS_WAITING_TO_SEND_CLOSE &&
|
||||
lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK)) {
|
||||
//assert(0);
|
||||
lwsl_debug("binning %d %d\n", lwsi_state(wsi), *wp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return lws_issue_raw(wsi, (unsigned char *)buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn)
|
||||
{
|
||||
lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if (lwsi_role_client(wsi)) {
|
||||
/*
|
||||
* If alpn asserts it is http/1.1, server support for KA is
|
||||
* mandatory.
|
||||
*
|
||||
* Knowing this lets us proceed with sending pipelined headers
|
||||
* before we received the first response headers.
|
||||
*/
|
||||
wsi->keepalive_active = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_destroy_role_h1(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct allocated_headers *ah;
|
||||
|
||||
/* we may not have an ah, but may be on the waiting list... */
|
||||
lwsl_info("%s: ah det due to close\n", __func__);
|
||||
__lws_header_table_detach(wsi, 0);
|
||||
|
||||
ah = pt->http.ah_list;
|
||||
|
||||
while (ah) {
|
||||
if (ah->in_use && ah->wsi == wsi) {
|
||||
lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
|
||||
ah->in_use = 0;
|
||||
ah->wsi = NULL;
|
||||
pt->http.ah_count_in_use--;
|
||||
break;
|
||||
}
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
#ifdef LWS_ROLE_WS
|
||||
lws_free_set_NULL(wsi->ws);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_h1 = {
|
||||
/* role name */ "h1",
|
||||
/* alpn id */ "http/1.1",
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_h1,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_h1,
|
||||
/* perform_user_POLLOUT */ NULL,
|
||||
/* callback_on_writable */ NULL,
|
||||
/* tx_credit */ NULL,
|
||||
/* write_role_protocol */ rops_write_role_protocol_h1,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ rops_alpn_negotiated_h1,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* destroy_role */ rops_destroy_role_h1,
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_CLIENT_HTTP_WRITEABLE,
|
||||
LWS_CALLBACK_HTTP_WRITEABLE },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
|
||||
LWS_CALLBACK_CLOSED_HTTP },
|
||||
/* file_handle */ 0,
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h if LWS_ROLE_H1
|
||||
*
|
||||
* Most of the h1 business is defined in the h1 / h2 common roles/http dir
|
||||
*/
|
||||
|
||||
extern struct lws_role_ops role_ops_h1;
|
||||
#define lwsi_role_h1(wsi) (wsi->role_ops == &role_ops_h1)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
#include "lextable-strings.h"
|
||||
|
||||
|
||||
const unsigned char *
|
||||
lws_token_to_string(enum lws_token_indexes token)
|
||||
{
|
||||
if ((unsigned int)token >= LWS_ARRAY_SIZE(set))
|
||||
return NULL;
|
||||
|
||||
return (unsigned char *)set[token];
|
||||
}
|
||||
|
||||
int
|
||||
lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
|
||||
const unsigned char *value, int length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
|
||||
return lws_add_http2_header_by_name(wsi, name,
|
||||
value, length, p, end);
|
||||
#else
|
||||
(void)wsi;
|
||||
#endif
|
||||
if (name) {
|
||||
while (*p < end && *name)
|
||||
*((*p)++) = *name++;
|
||||
if (*p == end)
|
||||
return 1;
|
||||
*((*p)++) = ' ';
|
||||
}
|
||||
if (*p + length + 3 >= end)
|
||||
return 1;
|
||||
|
||||
memcpy(*p, value, length);
|
||||
*p += length;
|
||||
*((*p)++) = '\x0d';
|
||||
*((*p)++) = '\x0a';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
|
||||
unsigned char *end)
|
||||
{
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
|
||||
return 0;
|
||||
#else
|
||||
(void)wsi;
|
||||
#endif
|
||||
if ((lws_intptr_t)(end - *p) < 3)
|
||||
return 1;
|
||||
*((*p)++) = '\x0d';
|
||||
*((*p)++) = '\x0a';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_finalize_write_http_header(struct lws *wsi, unsigned char *start,
|
||||
unsigned char **pp, unsigned char *end)
|
||||
{
|
||||
unsigned char *p;
|
||||
int len;
|
||||
|
||||
if (lws_finalize_http_header(wsi, pp, end))
|
||||
return 1;
|
||||
|
||||
p = *pp;
|
||||
len = lws_ptr_diff(p, start);
|
||||
|
||||
if (lws_write(wsi, start, len, LWS_WRITE_HTTP_HEADERS) != len)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
||||
const unsigned char *value, int length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
const unsigned char *name;
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
|
||||
return lws_add_http2_header_by_token(wsi, token, value,
|
||||
length, p, end);
|
||||
#endif
|
||||
name = lws_token_to_string(token);
|
||||
if (!name)
|
||||
return 1;
|
||||
|
||||
return lws_add_http_header_by_name(wsi, name, value, length, p, end);
|
||||
}
|
||||
|
||||
int lws_add_http_header_content_length(struct lws *wsi,
|
||||
lws_filepos_t content_length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
char b[24];
|
||||
int n;
|
||||
|
||||
n = sprintf(b, "%llu", (unsigned long long)content_length);
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)b, n, p, end))
|
||||
return 1;
|
||||
wsi->http.tx_content_length = content_length;
|
||||
wsi->http.tx_content_remain = content_length;
|
||||
|
||||
lwsl_info("%s: wsi %p: tx_content_length/remain %llu\n", __func__,
|
||||
wsi, (unsigned long long)content_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_add_http_common_headers(struct lws *wsi, unsigned int code,
|
||||
const char *content_type, lws_filepos_t content_len,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
if (lws_add_http_header_status(wsi, code, p, end))
|
||||
return 1;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)content_type,
|
||||
(int)strlen(content_type), p, end))
|
||||
return 1;
|
||||
|
||||
if (content_len != LWS_ILLEGAL_HTTP_CONTENT_LEN) {
|
||||
if (lws_add_http_header_content_length(wsi, content_len, p, end))
|
||||
return 1;
|
||||
} else {
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
|
||||
(unsigned char *)"close", 5,
|
||||
p, end))
|
||||
return 1;
|
||||
|
||||
wsi->http.connection_type = HTTP_CONNECTION_CLOSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STORE_IN_ROM static const char * const err400[] = {
|
||||
"Bad Request",
|
||||
"Unauthorized",
|
||||
"Payment Required",
|
||||
"Forbidden",
|
||||
"Not Found",
|
||||
"Method Not Allowed",
|
||||
"Not Acceptable",
|
||||
"Proxy Auth Required",
|
||||
"Request Timeout",
|
||||
"Conflict",
|
||||
"Gone",
|
||||
"Length Required",
|
||||
"Precondition Failed",
|
||||
"Request Entity Too Large",
|
||||
"Request URI too Long",
|
||||
"Unsupported Media Type",
|
||||
"Requested Range Not Satisfiable",
|
||||
"Expectation Failed"
|
||||
};
|
||||
|
||||
STORE_IN_ROM static const char * const err500[] = {
|
||||
"Internal Server Error",
|
||||
"Not Implemented",
|
||||
"Bad Gateway",
|
||||
"Service Unavailable",
|
||||
"Gateway Timeout",
|
||||
"HTTP Version Not Supported"
|
||||
};
|
||||
|
||||
int
|
||||
lws_add_http_header_status(struct lws *wsi, unsigned int _code,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
STORE_IN_ROM static const char * const hver[] = {
|
||||
"HTTP/1.0", "HTTP/1.1", "HTTP/2"
|
||||
};
|
||||
const struct lws_protocol_vhost_options *headers;
|
||||
unsigned int code = _code & LWSAHH_CODE_MASK;
|
||||
const char *description = "", *p1;
|
||||
unsigned char code_and_desc[60];
|
||||
int n;
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
wsi->http.access_log.response = code;
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi)) {
|
||||
n = lws_add_http2_header_status(wsi, code, p, end);
|
||||
if (n)
|
||||
return n;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (code >= 400 && code < (400 + LWS_ARRAY_SIZE(err400)))
|
||||
description = err400[code - 400];
|
||||
if (code >= 500 && code < (500 + LWS_ARRAY_SIZE(err500)))
|
||||
description = err500[code - 500];
|
||||
|
||||
if (code == 100)
|
||||
description = "Continue";
|
||||
if (code == 200)
|
||||
description = "OK";
|
||||
if (code == 304)
|
||||
description = "Not Modified";
|
||||
else
|
||||
if (code >= 300 && code < 400)
|
||||
description = "Redirect";
|
||||
|
||||
if (wsi->http.request_version < LWS_ARRAY_SIZE(hver))
|
||||
p1 = hver[wsi->http.request_version];
|
||||
else
|
||||
p1 = hver[0];
|
||||
|
||||
n = sprintf((char *)code_and_desc, "%s %u %s", p1, code,
|
||||
description);
|
||||
|
||||
if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p,
|
||||
end))
|
||||
return 1;
|
||||
}
|
||||
headers = wsi->vhost->headers;
|
||||
while (headers) {
|
||||
if (lws_add_http_header_by_name(wsi,
|
||||
(const unsigned char *)headers->name,
|
||||
(unsigned char *)headers->value,
|
||||
(int)strlen(headers->value), p, end))
|
||||
return 1;
|
||||
|
||||
headers = headers->next;
|
||||
}
|
||||
|
||||
if (wsi->context->server_string &&
|
||||
!(_code & LWSAHH_FLAG_NO_SERVER_NAME))
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
|
||||
(unsigned char *)wsi->context->server_string,
|
||||
wsi->context->server_string_len, p, end))
|
||||
return 1;
|
||||
|
||||
if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
|
||||
if (lws_add_http_header_by_name(wsi, (unsigned char *)
|
||||
"Strict-Transport-Security:",
|
||||
(unsigned char *)"max-age=15768000 ; "
|
||||
"includeSubDomains", 36, p, end))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_return_http_status(struct lws *wsi, unsigned int code,
|
||||
const char *html_body)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
unsigned char *p = pt->serv_buf + LWS_PRE;
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
|
||||
int n = 0, m = 0, len;
|
||||
char slen[20];
|
||||
|
||||
if (!wsi->vhost) {
|
||||
lwsl_err("%s: wsi not bound to vhost\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
if (!wsi->handling_404 &&
|
||||
wsi->vhost->http.error_document_404 &&
|
||||
code == HTTP_STATUS_NOT_FOUND)
|
||||
/* we should do a redirect, and do the 404 there */
|
||||
if (lws_http_redirect(wsi, HTTP_STATUS_FOUND,
|
||||
(uint8_t *)wsi->vhost->http.error_document_404,
|
||||
(int)strlen(wsi->vhost->http.error_document_404),
|
||||
&p, end) > 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* if the redirect failed, just do a simple status */
|
||||
p = start;
|
||||
|
||||
if (!html_body)
|
||||
html_body = "";
|
||||
|
||||
if (lws_add_http_header_status(wsi, code, &p, end))
|
||||
return 1;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)"text/html", 9,
|
||||
&p, end))
|
||||
return 1;
|
||||
|
||||
len = 35 + (int)strlen(html_body) + sprintf(slen, "%d", code);
|
||||
n = sprintf(slen, "%d", len);
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)slen, n, &p, end))
|
||||
return 1;
|
||||
|
||||
if (lws_finalize_http_header(wsi, &p, end))
|
||||
return 1;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->http2_substream) {
|
||||
unsigned char *body = p + 512;
|
||||
|
||||
/*
|
||||
* for HTTP/2, the headers must be sent separately, since they
|
||||
* go out in their own frame. That puts us in a bind that
|
||||
* we won't always be able to get away with two lws_write()s in
|
||||
* sequence, since the first may use up the writability due to
|
||||
* the pipe being choked or SSL_WANT_.
|
||||
*
|
||||
* However we do need to send the human-readable body, and the
|
||||
* END_STREAM.
|
||||
*
|
||||
* Solve it by writing the headers now...
|
||||
*/
|
||||
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
if (m != lws_ptr_diff(p, start))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* ... but stash the body and send it as a priority next
|
||||
* handle_POLLOUT
|
||||
*/
|
||||
|
||||
len = sprintf((char *)body,
|
||||
"<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
wsi->http.tx_content_length = len;
|
||||
wsi->http.tx_content_remain = len;
|
||||
|
||||
wsi->h2.pending_status_body = lws_malloc(len + LWS_PRE + 1,
|
||||
"pending status body");
|
||||
if (!wsi->h2.pending_status_body)
|
||||
return -1;
|
||||
|
||||
strcpy(wsi->h2.pending_status_body + LWS_PRE,
|
||||
(const char *)body);
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* for http/1, we can just append the body after the finalized
|
||||
* headers and send it all in one go.
|
||||
*/
|
||||
p += lws_snprintf((char *)p, end - p - 1,
|
||||
"<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
|
||||
n = lws_ptr_diff(p, start);
|
||||
m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
|
||||
if (m != n)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return m != n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
unsigned char *start = *p;
|
||||
|
||||
if (lws_add_http_header_status(wsi, code, p, end))
|
||||
return -1;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION, loc, len,
|
||||
p, end))
|
||||
return -1;
|
||||
/*
|
||||
* if we're going with http/1.1 and keepalive, we have to give fake
|
||||
* content metadata so the client knows we completed the transaction and
|
||||
* it can do the redirect...
|
||||
*/
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)"text/html", 9, p,
|
||||
end))
|
||||
return -1;
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)"0", 1, p, end))
|
||||
return -1;
|
||||
|
||||
if (lws_finalize_http_header(wsi, p, end))
|
||||
return -1;
|
||||
|
||||
return lws_write(wsi, start, *p - start, LWS_WRITE_HTTP_HEADERS |
|
||||
LWS_WRITE_H2_STREAM_END);
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/* set of parsable strings -- ALL LOWER CASE */
|
||||
|
||||
#if !defined(STORE_IN_ROM)
|
||||
#define STORE_IN_ROM
|
||||
#endif
|
||||
|
||||
STORE_IN_ROM static const char * const 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:",
|
||||
|
||||
"patch",
|
||||
"put",
|
||||
"delete",
|
||||
|
||||
"uri-args", /* fake header used for uri-only storage */
|
||||
|
||||
"proxy ",
|
||||
"x-real-ip:",
|
||||
"http/1.0 ",
|
||||
|
||||
"x-forwarded-for",
|
||||
"connect ",
|
||||
"head ",
|
||||
"te:", /* http/2 wants it to reject it */
|
||||
"replay-nonce:", /* ACME */
|
||||
":protocol", /* defined in mcmanus-httpbis-h2-ws-02 */
|
||||
|
||||
"x-auth-token:",
|
||||
|
||||
"", /* not matchable */
|
||||
|
||||
};
|
|
@ -1,838 +0,0 @@
|
|||
/* pos 0000: 0 */ 0x67 /* 'g' */, 0x40, 0x00 /* (to 0x0040 state 1) */,
|
||||
0x70 /* 'p' */, 0x42, 0x00 /* (to 0x0045 state 5) */,
|
||||
0x6F /* 'o' */, 0x51, 0x00 /* (to 0x0057 state 10) */,
|
||||
0x68 /* 'h' */, 0x5D, 0x00 /* (to 0x0066 state 18) */,
|
||||
0x63 /* 'c' */, 0x69, 0x00 /* (to 0x0075 state 23) */,
|
||||
0x75 /* 'u' */, 0x8A, 0x00 /* (to 0x0099 state 34) */,
|
||||
0x73 /* 's' */, 0xA0, 0x00 /* (to 0x00B2 state 48) */,
|
||||
0x0D /* '.' */, 0xD9, 0x00 /* (to 0x00EE state 68) */,
|
||||
0x61 /* 'a' */, 0x31, 0x01 /* (to 0x0149 state 129) */,
|
||||
0x69 /* 'i' */, 0x70, 0x01 /* (to 0x018B state 163) */,
|
||||
0x64 /* 'd' */, 0x19, 0x02 /* (to 0x0237 state 265) */,
|
||||
0x72 /* 'r' */, 0x22, 0x02 /* (to 0x0243 state 270) */,
|
||||
0x3A /* ':' */, 0x56, 0x02 /* (to 0x027A state 299) */,
|
||||
0x65 /* 'e' */, 0xE8, 0x02 /* (to 0x030F state 409) */,
|
||||
0x66 /* 'f' */, 0x04, 0x03 /* (to 0x032E state 425) */,
|
||||
0x6C /* 'l' */, 0x26, 0x03 /* (to 0x0353 state 458) */,
|
||||
0x6D /* 'm' */, 0x49, 0x03 /* (to 0x0379 state 484) */,
|
||||
0x74 /* 't' */, 0xB8, 0x03 /* (to 0x03EB state 578) */,
|
||||
0x76 /* 'v' */, 0xD9, 0x03 /* (to 0x040F state 606) */,
|
||||
0x77 /* 'w' */, 0xE6, 0x03 /* (to 0x041F state 614) */,
|
||||
0x78 /* 'x' */, 0x0D, 0x04 /* (to 0x0449 state 650) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0040: 1 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0041: 2 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0042: 3 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0043: 4 */ 0x00, 0x00 /* - terminal marker 0 - */,
|
||||
/* pos 0045: 5 */ 0x6F /* 'o' */, 0x0D, 0x00 /* (to 0x0052 state 6) */,
|
||||
0x72 /* 'r' */, 0x95, 0x01 /* (to 0x01DD state 211) */,
|
||||
0x61 /* 'a' */, 0xE6, 0x03 /* (to 0x0431 state 631) */,
|
||||
0x75 /* 'u' */, 0xE8, 0x03 /* (to 0x0436 state 635) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0052: 6 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0053: 7 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0054: 8 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0055: 9 */ 0x00, 0x01 /* - terminal marker 1 - */,
|
||||
/* pos 0057: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x005E state 11) */,
|
||||
0x72 /* 'r' */, 0x51, 0x00 /* (to 0x00AB state 42) */,
|
||||
0x08, /* fail */
|
||||
/* pos 005e: 11 */ 0xF4 /* 't' -> */,
|
||||
/* pos 005f: 12 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0060: 13 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0061: 14 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0062: 15 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0063: 16 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0064: 17 */ 0x00, 0x02 /* - terminal marker 2 - */,
|
||||
/* pos 0066: 18 */ 0x6F /* 'o' */, 0x0A, 0x00 /* (to 0x0070 state 19) */,
|
||||
0x74 /* 't' */, 0xBF, 0x00 /* (to 0x0128 state 110) */,
|
||||
0x65 /* 'e' */, 0x04, 0x04 /* (to 0x0470 state 676) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0070: 19 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0071: 20 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0072: 21 */ 0xBA /* ':' -> */,
|
||||
/* pos 0073: 22 */ 0x00, 0x03 /* - terminal marker 3 - */,
|
||||
/* pos 0075: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x007C state 24) */,
|
||||
0x61 /* 'a' */, 0x72, 0x01 /* (to 0x01EA state 217) */,
|
||||
0x08, /* fail */
|
||||
/* pos 007c: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0083 state 25) */,
|
||||
0x6F /* 'o' */, 0x87, 0x01 /* (to 0x0206 state 243) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0083: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x008A state 26) */,
|
||||
0x74 /* 't' */, 0x86, 0x01 /* (to 0x020C state 248) */,
|
||||
0x08, /* fail */
|
||||
/* pos 008a: 26 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 008b: 27 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 008c: 28 */ 0xF4 /* 't' -> */,
|
||||
/* pos 008d: 29 */ 0x69 /* 'i' */, 0x07, 0x00 /* (to 0x0094 state 30) */,
|
||||
0x20 /* ' ' */, 0xDE, 0x03 /* (to 0x046E state 675) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0094: 30 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0095: 31 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0096: 32 */ 0xBA /* ':' -> */,
|
||||
/* pos 0097: 33 */ 0x00, 0x04 /* - terminal marker 4 - */,
|
||||
/* pos 0099: 34 */ 0x70 /* 'p' */, 0x0A, 0x00 /* (to 0x00A3 state 35) */,
|
||||
0x73 /* 's' */, 0x68, 0x03 /* (to 0x0404 state 596) */,
|
||||
0x72 /* 'r' */, 0xA0, 0x03 /* (to 0x043F state 642) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00a3: 35 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 00a4: 36 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00a5: 37 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 00a6: 38 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 00a7: 39 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00a8: 40 */ 0xBA /* ':' -> */,
|
||||
/* pos 00a9: 41 */ 0x00, 0x05 /* - terminal marker 5 - */,
|
||||
/* pos 00ab: 42 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00ac: 43 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 00ad: 44 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00ae: 45 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00af: 46 */ 0xBA /* ':' -> */,
|
||||
/* pos 00b0: 47 */ 0x00, 0x06 /* - terminal marker 6 - */,
|
||||
/* pos 00b2: 48 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x00B9 state 49) */,
|
||||
0x74 /* 't' */, 0x1C, 0x03 /* (to 0x03D1 state 553) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00b9: 49 */ 0x63 /* 'c' */, 0x0A, 0x00 /* (to 0x00C3 state 50) */,
|
||||
0x72 /* 'r' */, 0x05, 0x03 /* (to 0x03C1 state 539) */,
|
||||
0x74 /* 't' */, 0x08, 0x03 /* (to 0x03C7 state 544) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00c3: 50 */ 0xAD /* '-' -> */,
|
||||
/* pos 00c4: 51 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 00c5: 52 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00c6: 53 */ 0xE2 /* 'b' -> */,
|
||||
/* pos 00c7: 54 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00c8: 55 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00c9: 56 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 00ca: 57 */ 0xEB /* 'k' -> */,
|
||||
/* pos 00cb: 58 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00cc: 59 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00cd: 60 */ 0xAD /* '-' -> */,
|
||||
/* pos 00ce: 61 */ 0x64 /* 'd' */, 0x19, 0x00 /* (to 0x00E7 state 62) */,
|
||||
0x65 /* 'e' */, 0x20, 0x00 /* (to 0x00F1 state 70) */,
|
||||
0x6B /* 'k' */, 0x29, 0x00 /* (to 0x00FD state 81) */,
|
||||
0x70 /* 'p' */, 0x38, 0x00 /* (to 0x010F state 88) */,
|
||||
0x61 /* 'a' */, 0x3F, 0x00 /* (to 0x0119 state 97) */,
|
||||
0x6E /* 'n' */, 0x44, 0x00 /* (to 0x0121 state 104) */,
|
||||
0x76 /* 'v' */, 0x89, 0x01 /* (to 0x0269 state 284) */,
|
||||
0x6F /* 'o' */, 0x8F, 0x01 /* (to 0x0272 state 292) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00e7: 62 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00e8: 63 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 00e9: 64 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 00ea: 65 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00eb: 66 */ 0xBA /* ':' -> */,
|
||||
/* pos 00ec: 67 */ 0x00, 0x07 /* - terminal marker 7 - */,
|
||||
/* pos 00ee: 68 */ 0x8A /* '.' -> */,
|
||||
/* pos 00ef: 69 */ 0x00, 0x08 /* - terminal marker 8 - */,
|
||||
/* pos 00f1: 70 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 00f2: 71 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00f3: 72 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00f4: 73 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00f5: 74 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00f6: 75 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00f7: 76 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00f8: 77 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00f9: 78 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00fa: 79 */ 0xBA /* ':' -> */,
|
||||
/* pos 00fb: 80 */ 0x00, 0x09 /* - terminal marker 9 - */,
|
||||
/* pos 00fd: 81 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00fe: 82 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 00ff: 83 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x0109 state 84) */,
|
||||
0x32 /* '2' */, 0x0A, 0x00 /* (to 0x010C state 86) */,
|
||||
0x3A /* ':' */, 0x62, 0x01 /* (to 0x0267 state 283) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0109: 84 */ 0xBA /* ':' -> */,
|
||||
/* pos 010a: 85 */ 0x00, 0x0A /* - terminal marker 10 - */,
|
||||
/* pos 010c: 86 */ 0xBA /* ':' -> */,
|
||||
/* pos 010d: 87 */ 0x00, 0x0B /* - terminal marker 11 - */,
|
||||
/* pos 010f: 88 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0110: 89 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0111: 90 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0112: 91 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0113: 92 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0114: 93 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0115: 94 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0116: 95 */ 0xBA /* ':' -> */,
|
||||
/* pos 0117: 96 */ 0x00, 0x0C /* - terminal marker 12 - */,
|
||||
/* pos 0119: 97 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 011a: 98 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 011b: 99 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 011c: 100 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 011d: 101 */ 0xF4 /* 't' -> */,
|
||||
/* pos 011e: 102 */ 0xBA /* ':' -> */,
|
||||
/* pos 011f: 103 */ 0x00, 0x0D /* - terminal marker 13 - */,
|
||||
/* pos 0121: 104 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0122: 105 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0123: 106 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0124: 107 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0125: 108 */ 0xBA /* ':' -> */,
|
||||
/* pos 0126: 109 */ 0x00, 0x0E /* - terminal marker 14 - */,
|
||||
/* pos 0128: 110 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0129: 111 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 012a: 112 */ 0x2F /* '/' */, 0x07, 0x00 /* (to 0x0131 state 113) */,
|
||||
0x32 /* '2' */, 0x10, 0x00 /* (to 0x013D state 118) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0131: 113 */ 0xB1 /* '1' -> */,
|
||||
/* pos 0132: 114 */ 0xAE /* '.' -> */,
|
||||
/* pos 0133: 115 */ 0x31 /* '1' */, 0x07, 0x00 /* (to 0x013A state 116) */,
|
||||
0x30 /* '0' */, 0x27, 0x03 /* (to 0x045D state 660) */,
|
||||
0x08, /* fail */
|
||||
/* pos 013a: 116 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 013b: 117 */ 0x00, 0x0F /* - terminal marker 15 - */,
|
||||
/* pos 013d: 118 */ 0xAD /* '-' -> */,
|
||||
/* pos 013e: 119 */ 0xF3 /* 's' -> */,
|
||||
/* pos 013f: 120 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0140: 121 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0141: 122 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0142: 123 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0143: 124 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0144: 125 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0145: 126 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0146: 127 */ 0xBA /* ':' -> */,
|
||||
/* pos 0147: 128 */ 0x00, 0x10 /* - terminal marker 16 - */,
|
||||
/* pos 0149: 129 */ 0x63 /* 'c' */, 0x0D, 0x00 /* (to 0x0156 state 130) */,
|
||||
0x75 /* 'u' */, 0xAC, 0x00 /* (to 0x01F8 state 230) */,
|
||||
0x67 /* 'g' */, 0x86, 0x01 /* (to 0x02D5 state 358) */,
|
||||
0x6C /* 'l' */, 0x87, 0x01 /* (to 0x02D9 state 361) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0156: 130 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0157: 131 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0158: 132 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x015F state 133) */,
|
||||
0x73 /* 's' */, 0x0E, 0x00 /* (to 0x0169 state 136) */,
|
||||
0x08, /* fail */
|
||||
/* pos 015f: 133 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0160: 134 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x0167 state 135) */,
|
||||
0x2D /* '-' */, 0x59, 0x00 /* (to 0x01BC state 192) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0167: 135 */ 0x00, 0x11 /* - terminal marker 17 - */,
|
||||
/* pos 0169: 136 */ 0xF3 /* 's' -> */,
|
||||
/* pos 016a: 137 */ 0xAD /* '-' -> */,
|
||||
/* pos 016b: 138 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 016c: 139 */ 0xEF /* 'o' -> */,
|
||||
/* pos 016d: 140 */ 0xEE /* 'n' -> */,
|
||||
/* pos 016e: 141 */ 0xF4 /* 't' -> */,
|
||||
/* pos 016f: 142 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0170: 143 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0171: 144 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0172: 145 */ 0xAD /* '-' -> */,
|
||||
/* pos 0173: 146 */ 0x72 /* 'r' */, 0x07, 0x00 /* (to 0x017A state 147) */,
|
||||
0x61 /* 'a' */, 0x51, 0x01 /* (to 0x02C7 state 345) */,
|
||||
0x08, /* fail */
|
||||
/* pos 017a: 147 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 017b: 148 */ 0xF1 /* 'q' -> */,
|
||||
/* pos 017c: 149 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 017d: 150 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 017e: 151 */ 0xF3 /* 's' -> */,
|
||||
/* pos 017f: 152 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0180: 153 */ 0xAD /* '-' -> */,
|
||||
/* pos 0181: 154 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0182: 155 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0183: 156 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0184: 157 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0185: 158 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0186: 159 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0187: 160 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0188: 161 */ 0xBA /* ':' -> */,
|
||||
/* pos 0189: 162 */ 0x00, 0x12 /* - terminal marker 18 - */,
|
||||
/* pos 018b: 163 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 018c: 164 */ 0xAD /* '-' -> */,
|
||||
/* pos 018d: 165 */ 0x6D /* 'm' */, 0x0D, 0x00 /* (to 0x019A state 166) */,
|
||||
0x6E /* 'n' */, 0x20, 0x00 /* (to 0x01B0 state 181) */,
|
||||
0x72 /* 'r' */, 0xA7, 0x01 /* (to 0x033A state 435) */,
|
||||
0x75 /* 'u' */, 0xAB, 0x01 /* (to 0x0341 state 441) */,
|
||||
0x08, /* fail */
|
||||
/* pos 019a: 166 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x01A1 state 167) */,
|
||||
0x61 /* 'a' */, 0x97, 0x01 /* (to 0x0334 state 430) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01a1: 167 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 01a2: 168 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01a3: 169 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 01a4: 170 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01a5: 171 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01a6: 172 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 01a7: 173 */ 0xAD /* '-' -> */,
|
||||
/* pos 01a8: 174 */ 0xF3 /* 's' -> */,
|
||||
/* pos 01a9: 175 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01aa: 176 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01ab: 177 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01ac: 178 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01ad: 179 */ 0xBA /* ':' -> */,
|
||||
/* pos 01ae: 180 */ 0x00, 0x13 /* - terminal marker 19 - */,
|
||||
/* pos 01b0: 181 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01b1: 182 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01b2: 183 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01b3: 184 */ 0xAD /* '-' -> */,
|
||||
/* pos 01b4: 185 */ 0xED /* 'm' -> */,
|
||||
/* pos 01b5: 186 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01b6: 187 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01b7: 188 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01b8: 189 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01b9: 190 */ 0xBA /* ':' -> */,
|
||||
/* pos 01ba: 191 */ 0x00, 0x14 /* - terminal marker 20 - */,
|
||||
/* pos 01bc: 192 */ 0x65 /* 'e' */, 0x0D, 0x00 /* (to 0x01C9 state 193) */,
|
||||
0x6C /* 'l' */, 0x14, 0x00 /* (to 0x01D3 state 202) */,
|
||||
0x63 /* 'c' */, 0xF4, 0x00 /* (to 0x02B6 state 330) */,
|
||||
0x72 /* 'r' */, 0xFA, 0x00 /* (to 0x02BF state 338) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01c9: 193 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01ca: 194 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01cb: 195 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01cc: 196 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 01cd: 197 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01ce: 198 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01cf: 199 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01d0: 200 */ 0xBA /* ':' -> */,
|
||||
/* pos 01d1: 201 */ 0x00, 0x15 /* - terminal marker 21 - */,
|
||||
/* pos 01d3: 202 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01d4: 203 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01d5: 204 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01d6: 205 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 01d7: 206 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01d8: 207 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01d9: 208 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01da: 209 */ 0xBA /* ':' -> */,
|
||||
/* pos 01db: 210 */ 0x00, 0x16 /* - terminal marker 22 - */,
|
||||
/* pos 01dd: 211 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01E4 state 212) */,
|
||||
0x6F /* 'o' */, 0xA7, 0x01 /* (to 0x0387 state 497) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01e4: 212 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01e5: 213 */ 0xED /* 'm' -> */,
|
||||
/* pos 01e6: 214 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01e7: 215 */ 0xBA /* ':' -> */,
|
||||
/* pos 01e8: 216 */ 0x00, 0x17 /* - terminal marker 23 - */,
|
||||
/* pos 01ea: 217 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01eb: 218 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01ec: 219 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01ed: 220 */ 0xAD /* '-' -> */,
|
||||
/* pos 01ee: 221 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01ef: 222 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01f0: 223 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01f1: 224 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01f2: 225 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 01f3: 226 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01f4: 227 */ 0xEC /* 'l' -> */,
|
||||
/* pos 01f5: 228 */ 0xBA /* ':' -> */,
|
||||
/* pos 01f6: 229 */ 0x00, 0x18 /* - terminal marker 24 - */,
|
||||
/* pos 01f8: 230 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01f9: 231 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01fa: 232 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01fb: 233 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 01fc: 234 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01fd: 235 */ 0xFA /* 'z' -> */,
|
||||
/* pos 01fe: 236 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01ff: 237 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0200: 238 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0201: 239 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0202: 240 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0203: 241 */ 0xBA /* ':' -> */,
|
||||
/* pos 0204: 242 */ 0x00, 0x19 /* - terminal marker 25 - */,
|
||||
/* pos 0206: 243 */ 0xEB /* 'k' -> */,
|
||||
/* pos 0207: 244 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0208: 245 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0209: 246 */ 0xBA /* ':' -> */,
|
||||
/* pos 020a: 247 */ 0x00, 0x1A /* - terminal marker 26 - */,
|
||||
/* pos 020c: 248 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 020d: 249 */ 0xEE /* 'n' -> */,
|
||||
/* pos 020e: 250 */ 0xF4 /* 't' -> */,
|
||||
/* pos 020f: 251 */ 0xAD /* '-' -> */,
|
||||
/* pos 0210: 252 */ 0x6C /* 'l' */, 0x10, 0x00 /* (to 0x0220 state 253) */,
|
||||
0x74 /* 't' */, 0x1E, 0x00 /* (to 0x0231 state 260) */,
|
||||
0x64 /* 'd' */, 0xC9, 0x00 /* (to 0x02DF state 366) */,
|
||||
0x65 /* 'e' */, 0xD3, 0x00 /* (to 0x02EC state 378) */,
|
||||
0x72 /* 'r' */, 0xEC, 0x00 /* (to 0x0308 state 403) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0220: 253 */ 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x022A state 254) */,
|
||||
0x61 /* 'a' */, 0xD3, 0x00 /* (to 0x02F6 state 387) */,
|
||||
0x6F /* 'o' */, 0xD9, 0x00 /* (to 0x02FF state 395) */,
|
||||
0x08, /* fail */
|
||||
/* pos 022a: 254 */ 0xEE /* 'n' -> */,
|
||||
/* pos 022b: 255 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 022c: 256 */ 0xF4 /* 't' -> */,
|
||||
/* pos 022d: 257 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 022e: 258 */ 0xBA /* ':' -> */,
|
||||
/* pos 022f: 259 */ 0x00, 0x1B /* - terminal marker 27 - */,
|
||||
/* pos 0231: 260 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0232: 261 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 0233: 262 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0234: 263 */ 0xBA /* ':' -> */,
|
||||
/* pos 0235: 264 */ 0x00, 0x1C /* - terminal marker 28 - */,
|
||||
/* pos 0237: 265 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x023E state 266) */,
|
||||
0x65 /* 'e' */, 0xFF, 0x01 /* (to 0x0439 state 637) */,
|
||||
0x08, /* fail */
|
||||
/* pos 023e: 266 */ 0xF4 /* 't' -> */,
|
||||
/* pos 023f: 267 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0240: 268 */ 0xBA /* ':' -> */,
|
||||
/* pos 0241: 269 */ 0x00, 0x1D /* - terminal marker 29 - */,
|
||||
/* pos 0243: 270 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x024A state 271) */,
|
||||
0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x0250 state 276) */,
|
||||
0x08, /* fail */
|
||||
/* pos 024a: 271 */ 0xEE /* 'n' -> */,
|
||||
/* pos 024b: 272 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 024c: 273 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 024d: 274 */ 0xBA /* ':' -> */,
|
||||
/* pos 024e: 275 */ 0x00, 0x1E /* - terminal marker 30 - */,
|
||||
/* pos 0250: 276 */ 0x66 /* 'f' */, 0x0A, 0x00 /* (to 0x025A state 277) */,
|
||||
0x74 /* 't' */, 0x63, 0x01 /* (to 0x03B6 state 529) */,
|
||||
0x70 /* 'p' */, 0x22, 0x02 /* (to 0x0478 state 682) */,
|
||||
0x08, /* fail */
|
||||
/* pos 025a: 277 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0261 state 278) */,
|
||||
0x72 /* 'r' */, 0x53, 0x01 /* (to 0x03B0 state 524) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0261: 278 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0262: 279 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0263: 280 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0264: 281 */ 0xBA /* ':' -> */,
|
||||
/* pos 0265: 282 */ 0x00, 0x1F /* - terminal marker 31 - */,
|
||||
/* pos 0267: 283 */ 0x00, 0x20 /* - terminal marker 32 - */,
|
||||
/* pos 0269: 284 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 026a: 285 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 026b: 286 */ 0xF3 /* 's' -> */,
|
||||
/* pos 026c: 287 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 026d: 288 */ 0xEF /* 'o' -> */,
|
||||
/* pos 026e: 289 */ 0xEE /* 'n' -> */,
|
||||
/* pos 026f: 290 */ 0xBA /* ':' -> */,
|
||||
/* pos 0270: 291 */ 0x00, 0x21 /* - terminal marker 33 - */,
|
||||
/* pos 0272: 292 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0273: 293 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0274: 294 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0275: 295 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0276: 296 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0277: 297 */ 0xBA /* ':' -> */,
|
||||
/* pos 0278: 298 */ 0x00, 0x22 /* - terminal marker 34 - */,
|
||||
/* pos 027a: 299 */ 0x61 /* 'a' */, 0x0D, 0x00 /* (to 0x0287 state 300) */,
|
||||
0x6D /* 'm' */, 0x14, 0x00 /* (to 0x0291 state 309) */,
|
||||
0x70 /* 'p' */, 0x18, 0x00 /* (to 0x0298 state 315) */,
|
||||
0x73 /* 's' */, 0x20, 0x00 /* (to 0x02A3 state 319) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0287: 300 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 0288: 301 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0289: 302 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 028a: 303 */ 0xEF /* 'o' -> */,
|
||||
/* pos 028b: 304 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 028c: 305 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 028d: 306 */ 0xF4 /* 't' -> */,
|
||||
/* pos 028e: 307 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 028f: 308 */ 0x00, 0x23 /* - terminal marker 35 - */,
|
||||
/* pos 0291: 309 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0292: 310 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0293: 311 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0294: 312 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0295: 313 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0296: 314 */ 0x00, 0x24 /* - terminal marker 36 - */,
|
||||
/* pos 0298: 315 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x029F state 316) */,
|
||||
0x72 /* 'r' */, 0xE9, 0x01 /* (to 0x0484 state 693) */,
|
||||
0x08, /* fail */
|
||||
/* pos 029f: 316 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02a0: 317 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 02a1: 318 */ 0x00, 0x25 /* - terminal marker 37 - */,
|
||||
/* pos 02a3: 319 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x02AA state 320) */,
|
||||
0x74 /* 't' */, 0x0A, 0x00 /* (to 0x02B0 state 325) */,
|
||||
0x08, /* fail */
|
||||
/* pos 02aa: 320 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 02ab: 321 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02ac: 322 */ 0xED /* 'm' -> */,
|
||||
/* pos 02ad: 323 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02ae: 324 */ 0x00, 0x26 /* - terminal marker 38 - */,
|
||||
/* pos 02b0: 325 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02b1: 326 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02b2: 327 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 02b3: 328 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02b4: 329 */ 0x00, 0x27 /* - terminal marker 39 - */,
|
||||
/* pos 02b6: 330 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 02b7: 331 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02b8: 332 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 02b9: 333 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02ba: 334 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02bb: 335 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02bc: 336 */ 0xBA /* ':' -> */,
|
||||
/* pos 02bd: 337 */ 0x00, 0x28 /* - terminal marker 40 - */,
|
||||
/* pos 02bf: 338 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02c0: 339 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02c1: 340 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02c2: 341 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02c3: 342 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02c4: 343 */ 0xBA /* ':' -> */,
|
||||
/* pos 02c5: 344 */ 0x00, 0x29 /* - terminal marker 41 - */,
|
||||
/* pos 02c7: 345 */ 0xEC /* 'l' -> */,
|
||||
/* pos 02c8: 346 */ 0xEC /* 'l' -> */,
|
||||
/* pos 02c9: 347 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02ca: 348 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 02cb: 349 */ 0xAD /* '-' -> */,
|
||||
/* pos 02cc: 350 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02cd: 351 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 02ce: 352 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02cf: 353 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02d0: 354 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02d1: 355 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02d2: 356 */ 0xBA /* ':' -> */,
|
||||
/* pos 02d3: 357 */ 0x00, 0x2A /* - terminal marker 42 - */,
|
||||
/* pos 02d5: 358 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02d6: 359 */ 0xBA /* ':' -> */,
|
||||
/* pos 02d7: 360 */ 0x00, 0x2B /* - terminal marker 43 - */,
|
||||
/* pos 02d9: 361 */ 0xEC /* 'l' -> */,
|
||||
/* pos 02da: 362 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02db: 363 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 02dc: 364 */ 0xBA /* ':' -> */,
|
||||
/* pos 02dd: 365 */ 0x00, 0x2C /* - terminal marker 44 - */,
|
||||
/* pos 02df: 366 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02e0: 367 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02e1: 368 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 02e2: 369 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02e3: 370 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02e4: 371 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02e5: 372 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02e6: 373 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02e7: 374 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02e8: 375 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02e9: 376 */ 0xBA /* ':' -> */,
|
||||
/* pos 02ea: 377 */ 0x00, 0x2D /* - terminal marker 45 - */,
|
||||
/* pos 02ec: 378 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02ed: 379 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 02ee: 380 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02ef: 381 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 02f0: 382 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02f1: 383 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02f2: 384 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02f3: 385 */ 0xBA /* ':' -> */,
|
||||
/* pos 02f4: 386 */ 0x00, 0x2E /* - terminal marker 46 - */,
|
||||
/* pos 02f6: 387 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02f7: 388 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02f8: 389 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 02f9: 390 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02fa: 391 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02fb: 392 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02fc: 393 */ 0xBA /* ':' -> */,
|
||||
/* pos 02fd: 394 */ 0x00, 0x2F /* - terminal marker 47 - */,
|
||||
/* pos 02ff: 395 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0300: 396 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0301: 397 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0302: 398 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0303: 399 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0304: 400 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0305: 401 */ 0xBA /* ':' -> */,
|
||||
/* pos 0306: 402 */ 0x00, 0x30 /* - terminal marker 48 - */,
|
||||
/* pos 0308: 403 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0309: 404 */ 0xEE /* 'n' -> */,
|
||||
/* pos 030a: 405 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 030b: 406 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 030c: 407 */ 0xBA /* ':' -> */,
|
||||
/* pos 030d: 408 */ 0x00, 0x31 /* - terminal marker 49 - */,
|
||||
/* pos 030f: 409 */ 0x74 /* 't' */, 0x07, 0x00 /* (to 0x0316 state 410) */,
|
||||
0x78 /* 'x' */, 0x09, 0x00 /* (to 0x031B state 414) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0316: 410 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0317: 411 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0318: 412 */ 0xBA /* ':' -> */,
|
||||
/* pos 0319: 413 */ 0x00, 0x32 /* - terminal marker 50 - */,
|
||||
/* pos 031b: 414 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 031c: 415 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0323 state 416) */,
|
||||
0x69 /* 'i' */, 0x09, 0x00 /* (to 0x0328 state 420) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0323: 416 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0324: 417 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0325: 418 */ 0xBA /* ':' -> */,
|
||||
/* pos 0326: 419 */ 0x00, 0x33 /* - terminal marker 51 - */,
|
||||
/* pos 0328: 420 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0329: 421 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 032a: 422 */ 0xF3 /* 's' -> */,
|
||||
/* pos 032b: 423 */ 0xBA /* ':' -> */,
|
||||
/* pos 032c: 424 */ 0x00, 0x34 /* - terminal marker 52 - */,
|
||||
/* pos 032e: 425 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 032f: 426 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0330: 427 */ 0xED /* 'm' -> */,
|
||||
/* pos 0331: 428 */ 0xBA /* ':' -> */,
|
||||
/* pos 0332: 429 */ 0x00, 0x35 /* - terminal marker 53 - */,
|
||||
/* pos 0334: 430 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0335: 431 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0336: 432 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0337: 433 */ 0xBA /* ':' -> */,
|
||||
/* pos 0338: 434 */ 0x00, 0x36 /* - terminal marker 54 - */,
|
||||
/* pos 033a: 435 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 033b: 436 */ 0xEE /* 'n' -> */,
|
||||
/* pos 033c: 437 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 033d: 438 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 033e: 439 */ 0xBA /* ':' -> */,
|
||||
/* pos 033f: 440 */ 0x00, 0x37 /* - terminal marker 55 - */,
|
||||
/* pos 0341: 441 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0342: 442 */ 0xED /* 'm' -> */,
|
||||
/* pos 0343: 443 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0344: 444 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0345: 445 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0346: 446 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0347: 447 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0348: 448 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0349: 449 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 034a: 450 */ 0xAD /* '-' -> */,
|
||||
/* pos 034b: 451 */ 0xF3 /* 's' -> */,
|
||||
/* pos 034c: 452 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 034d: 453 */ 0xEE /* 'n' -> */,
|
||||
/* pos 034e: 454 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 034f: 455 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0350: 456 */ 0xBA /* ':' -> */,
|
||||
/* pos 0351: 457 */ 0x00, 0x38 /* - terminal marker 56 - */,
|
||||
/* pos 0353: 458 */ 0x61 /* 'a' */, 0x0A, 0x00 /* (to 0x035D state 459) */,
|
||||
0x69 /* 'i' */, 0x15, 0x00 /* (to 0x036B state 472) */,
|
||||
0x6F /* 'o' */, 0x17, 0x00 /* (to 0x0370 state 476) */,
|
||||
0x08, /* fail */
|
||||
/* pos 035d: 459 */ 0xF3 /* 's' -> */,
|
||||
/* pos 035e: 460 */ 0xF4 /* 't' -> */,
|
||||
/* pos 035f: 461 */ 0xAD /* '-' -> */,
|
||||
/* pos 0360: 462 */ 0xED /* 'm' -> */,
|
||||
/* pos 0361: 463 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0362: 464 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0363: 465 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0364: 466 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0365: 467 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0366: 468 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0367: 469 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0368: 470 */ 0xBA /* ':' -> */,
|
||||
/* pos 0369: 471 */ 0x00, 0x39 /* - terminal marker 57 - */,
|
||||
/* pos 036b: 472 */ 0xEE /* 'n' -> */,
|
||||
/* pos 036c: 473 */ 0xEB /* 'k' -> */,
|
||||
/* pos 036d: 474 */ 0xBA /* ':' -> */,
|
||||
/* pos 036e: 475 */ 0x00, 0x3A /* - terminal marker 58 - */,
|
||||
/* pos 0370: 476 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0371: 477 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0372: 478 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0373: 479 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0374: 480 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0375: 481 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0376: 482 */ 0xBA /* ':' -> */,
|
||||
/* pos 0377: 483 */ 0x00, 0x3B /* - terminal marker 59 - */,
|
||||
/* pos 0379: 484 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 037a: 485 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 037b: 486 */ 0xAD /* '-' -> */,
|
||||
/* pos 037c: 487 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 037d: 488 */ 0xEF /* 'o' -> */,
|
||||
/* pos 037e: 489 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 037f: 490 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0380: 491 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0381: 492 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0382: 493 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0383: 494 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0384: 495 */ 0xBA /* ':' -> */,
|
||||
/* pos 0385: 496 */ 0x00, 0x3C /* - terminal marker 60 - */,
|
||||
/* pos 0387: 497 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 0388: 498 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0389: 499 */ 0x2D /* '-' */, 0x07, 0x00 /* (to 0x0390 state 500) */,
|
||||
0x20 /* ' ' */, 0xBB, 0x00 /* (to 0x0447 state 649) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0390: 500 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0391: 501 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 0392: 502 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0393: 503 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0394: 504 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x039B state 505) */,
|
||||
0x6F /* 'o' */, 0x0E, 0x00 /* (to 0x03A5 state 514) */,
|
||||
0x08, /* fail */
|
||||
/* pos 039b: 505 */ 0xEE /* 'n' -> */,
|
||||
/* pos 039c: 506 */ 0xF4 /* 't' -> */,
|
||||
/* pos 039d: 507 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 039e: 508 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 039f: 509 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03a0: 510 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03a1: 511 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03a2: 512 */ 0xBA /* ':' -> */,
|
||||
/* pos 03a3: 513 */ 0x00, 0x3D /* - terminal marker 61 - */,
|
||||
/* pos 03a5: 514 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03a6: 515 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03a7: 516 */ 0xFA /* 'z' -> */,
|
||||
/* pos 03a8: 517 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03a9: 518 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03aa: 519 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03ab: 520 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03ac: 521 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03ad: 522 */ 0xBA /* ':' -> */,
|
||||
/* pos 03ae: 523 */ 0x00, 0x3E /* - terminal marker 62 - */,
|
||||
/* pos 03b0: 524 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03b1: 525 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03b2: 526 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 03b3: 527 */ 0xBA /* ':' -> */,
|
||||
/* pos 03b4: 528 */ 0x00, 0x3F /* - terminal marker 63 - */,
|
||||
/* pos 03b6: 529 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03b7: 530 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 03b8: 531 */ 0xAD /* '-' -> */,
|
||||
/* pos 03b9: 532 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03ba: 533 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 03bb: 534 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03bc: 535 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03bd: 536 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03be: 537 */ 0xBA /* ':' -> */,
|
||||
/* pos 03bf: 538 */ 0x00, 0x40 /* - terminal marker 64 - */,
|
||||
/* pos 03c1: 539 */ 0xF6 /* 'v' -> */,
|
||||
/* pos 03c2: 540 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03c3: 541 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03c4: 542 */ 0xBA /* ':' -> */,
|
||||
/* pos 03c5: 543 */ 0x00, 0x41 /* - terminal marker 65 - */,
|
||||
/* pos 03c7: 544 */ 0xAD /* '-' -> */,
|
||||
/* pos 03c8: 545 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03c9: 546 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03ca: 547 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03cb: 548 */ 0xEB /* 'k' -> */,
|
||||
/* pos 03cc: 549 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03cd: 550 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03ce: 551 */ 0xBA /* ':' -> */,
|
||||
/* pos 03cf: 552 */ 0x00, 0x42 /* - terminal marker 66 - */,
|
||||
/* pos 03d1: 553 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03d2: 554 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03d3: 555 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03d4: 556 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03d5: 557 */ 0xAD /* '-' -> */,
|
||||
/* pos 03d6: 558 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03d7: 559 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03d8: 560 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03d9: 561 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03da: 562 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03db: 563 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 03dc: 564 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03dd: 565 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03de: 566 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03df: 567 */ 0xAD /* '-' -> */,
|
||||
/* pos 03e0: 568 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03e1: 569 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03e2: 570 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03e3: 571 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 03e4: 572 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03e5: 573 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03e6: 574 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03e7: 575 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 03e8: 576 */ 0xBA /* ':' -> */,
|
||||
/* pos 03e9: 577 */ 0x00, 0x43 /* - terminal marker 67 - */,
|
||||
/* pos 03eb: 578 */ 0x72 /* 'r' */, 0x07, 0x00 /* (to 0x03F2 state 579) */,
|
||||
0x65 /* 'e' */, 0x87, 0x00 /* (to 0x0475 state 680) */,
|
||||
0x08, /* fail */
|
||||
/* pos 03f2: 579 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03f3: 580 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03f4: 581 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03f5: 582 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 03f6: 583 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03f7: 584 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03f8: 585 */ 0xAD /* '-' -> */,
|
||||
/* pos 03f9: 586 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03fa: 587 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03fb: 588 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03fc: 589 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03fd: 590 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 03fe: 591 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03ff: 592 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0400: 593 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0401: 594 */ 0xBA /* ':' -> */,
|
||||
/* pos 0402: 595 */ 0x00, 0x44 /* - terminal marker 68 - */,
|
||||
/* pos 0404: 596 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0405: 597 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0406: 598 */ 0xAD /* '-' -> */,
|
||||
/* pos 0407: 599 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0408: 600 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0409: 601 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 040a: 602 */ 0xEE /* 'n' -> */,
|
||||
/* pos 040b: 603 */ 0xF4 /* 't' -> */,
|
||||
/* pos 040c: 604 */ 0xBA /* ':' -> */,
|
||||
/* pos 040d: 605 */ 0x00, 0x45 /* - terminal marker 69 - */,
|
||||
/* pos 040f: 606 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0416 state 607) */,
|
||||
0x69 /* 'i' */, 0x09, 0x00 /* (to 0x041B state 611) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0416: 607 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0417: 608 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0418: 609 */ 0xBA /* ':' -> */,
|
||||
/* pos 0419: 610 */ 0x00, 0x46 /* - terminal marker 70 - */,
|
||||
/* pos 041b: 611 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 041c: 612 */ 0xBA /* ':' -> */,
|
||||
/* pos 041d: 613 */ 0x00, 0x47 /* - terminal marker 71 - */,
|
||||
/* pos 041f: 614 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0420: 615 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0421: 616 */ 0xAD /* '-' -> */,
|
||||
/* pos 0422: 617 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0423: 618 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 0424: 619 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0425: 620 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0426: 621 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0427: 622 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0428: 623 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0429: 624 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 042a: 625 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 042b: 626 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 042c: 627 */ 0xF4 /* 't' -> */,
|
||||
/* pos 042d: 628 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 042e: 629 */ 0xBA /* ':' -> */,
|
||||
/* pos 042f: 630 */ 0x00, 0x48 /* - terminal marker 72 - */,
|
||||
/* pos 0431: 631 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0432: 632 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0433: 633 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0434: 634 */ 0x00, 0x49 /* - terminal marker 73 - */,
|
||||
/* pos 0436: 635 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0437: 636 */ 0x00, 0x4A /* - terminal marker 74 - */,
|
||||
/* pos 0439: 637 */ 0xEC /* 'l' -> */,
|
||||
/* pos 043a: 638 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 043b: 639 */ 0xF4 /* 't' -> */,
|
||||
/* pos 043c: 640 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 043d: 641 */ 0x00, 0x4B /* - terminal marker 75 - */,
|
||||
/* pos 043f: 642 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0440: 643 */ 0xAD /* '-' -> */,
|
||||
/* pos 0441: 644 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0442: 645 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0443: 646 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0444: 647 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0445: 648 */ 0x00, 0x4C /* - terminal marker 76 - */,
|
||||
/* pos 0447: 649 */ 0x00, 0x4D /* - terminal marker 77 - */,
|
||||
/* pos 0449: 650 */ 0xAD /* '-' -> */,
|
||||
/* pos 044a: 651 */ 0x72 /* 'r' */, 0x0A, 0x00 /* (to 0x0454 state 652) */,
|
||||
0x66 /* 'f' */, 0x13, 0x00 /* (to 0x0460 state 662) */,
|
||||
0x61 /* 'a' */, 0x3C, 0x00 /* (to 0x048C state 700) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0454: 652 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0455: 653 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0456: 654 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0457: 655 */ 0xAD /* '-' -> */,
|
||||
/* pos 0458: 656 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0459: 657 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 045a: 658 */ 0xBA /* ':' -> */,
|
||||
/* pos 045b: 659 */ 0x00, 0x4E /* - terminal marker 78 - */,
|
||||
/* pos 045d: 660 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 045e: 661 */ 0x00, 0x4F /* - terminal marker 79 - */,
|
||||
/* pos 0460: 662 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0461: 663 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0462: 664 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0463: 665 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0464: 666 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0465: 667 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0466: 668 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0467: 669 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0468: 670 */ 0xAD /* '-' -> */,
|
||||
/* pos 0469: 671 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 046a: 672 */ 0xEF /* 'o' -> */,
|
||||
/* pos 046b: 673 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 046c: 674 */ 0x00, 0x50 /* - terminal marker 80 - */,
|
||||
/* pos 046e: 675 */ 0x00, 0x51 /* - terminal marker 81 - */,
|
||||
/* pos 0470: 676 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0471: 677 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0472: 678 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0473: 679 */ 0x00, 0x52 /* - terminal marker 82 - */,
|
||||
/* pos 0475: 680 */ 0xBA /* ':' -> */,
|
||||
/* pos 0476: 681 */ 0x00, 0x53 /* - terminal marker 83 - */,
|
||||
/* pos 0478: 682 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0479: 683 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 047a: 684 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 047b: 685 */ 0xAD /* '-' -> */,
|
||||
/* pos 047c: 686 */ 0xEE /* 'n' -> */,
|
||||
/* pos 047d: 687 */ 0xEF /* 'o' -> */,
|
||||
/* pos 047e: 688 */ 0xEE /* 'n' -> */,
|
||||
/* pos 047f: 689 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0480: 690 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0481: 691 */ 0xBA /* ':' -> */,
|
||||
/* pos 0482: 692 */ 0x00, 0x54 /* - terminal marker 84 - */,
|
||||
/* pos 0484: 693 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0485: 694 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0486: 695 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0487: 696 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0488: 697 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0489: 698 */ 0xEC /* 'l' -> */,
|
||||
/* pos 048a: 699 */ 0x00, 0x55 /* - terminal marker 85 - */,
|
||||
/* pos 048c: 700 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 048d: 701 */ 0xF4 /* 't' -> */,
|
||||
/* pos 048e: 702 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 048f: 703 */ 0xAD /* '-' -> */,
|
||||
/* pos 0490: 704 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0491: 705 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0492: 706 */ 0xEB /* 'k' -> */,
|
||||
/* pos 0493: 707 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0494: 708 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0495: 709 */ 0xBA /* ':' -> */,
|
||||
/* pos 0496: 710 */ 0x00, 0x56 /* - terminal marker 86 - */,
|
||||
/* total size 1176 bytes */
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h if either H1 or H2 roles are
|
||||
* enabled
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
#include <hubbub/hubbub.h>
|
||||
#include <hubbub/parser.h>
|
||||
#endif
|
||||
|
||||
#define lwsi_role_http(wsi) (lwsi_role_h1(wsi) || lwsi_role_h2(wsi))
|
||||
|
||||
enum http_version {
|
||||
HTTP_VERSION_1_0,
|
||||
HTTP_VERSION_1_1,
|
||||
HTTP_VERSION_2
|
||||
};
|
||||
|
||||
enum http_connection_type {
|
||||
HTTP_CONNECTION_CLOSE,
|
||||
HTTP_CONNECTION_KEEP_ALIVE
|
||||
};
|
||||
|
||||
/*
|
||||
* This is totally opaque to code using the library. It's exported as a
|
||||
* forward-reference pointer-only declaration; the user can use the pointer with
|
||||
* other APIs to get information out of it.
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
typedef uint16_t ah_data_idx_t;
|
||||
#else
|
||||
typedef uint32_t ah_data_idx_t;
|
||||
#endif
|
||||
|
||||
struct lws_fragments {
|
||||
ah_data_idx_t offset;
|
||||
uint16_t len;
|
||||
uint8_t nfrag; /* which ah->frag[] continues this content, or 0 */
|
||||
uint8_t flags; /* only http2 cares */
|
||||
};
|
||||
|
||||
#if defined(LWS_WITH_RANGES)
|
||||
enum range_states {
|
||||
LWSRS_NO_ACTIVE_RANGE,
|
||||
LWSRS_BYTES_EQ,
|
||||
LWSRS_FIRST,
|
||||
LWSRS_STARTING,
|
||||
LWSRS_ENDING,
|
||||
LWSRS_COMPLETED,
|
||||
LWSRS_SYNTAX,
|
||||
};
|
||||
|
||||
struct lws_range_parsing {
|
||||
unsigned long long start, end, extent, agg, budget;
|
||||
const char buf[128];
|
||||
int pos;
|
||||
enum range_states state;
|
||||
char start_valid, end_valid, ctr, count_ranges, did_try, inside, send_ctr;
|
||||
};
|
||||
|
||||
int
|
||||
lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
|
||||
unsigned long long extent);
|
||||
int
|
||||
lws_ranges_next(struct lws_range_parsing *rp);
|
||||
void
|
||||
lws_ranges_reset(struct lws_range_parsing *rp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* these are assigned from a pool held in the context.
|
||||
* Both client and server mode uses them for http header analysis
|
||||
*/
|
||||
|
||||
struct allocated_headers {
|
||||
struct allocated_headers *next; /* linked list */
|
||||
struct lws *wsi; /* owner */
|
||||
char *data; /* prepared by context init to point to dedicated storage */
|
||||
ah_data_idx_t data_length;
|
||||
/*
|
||||
* the randomly ordered fragments, indexed by frag_index and
|
||||
* lws_fragments->nfrag for continuation.
|
||||
*/
|
||||
struct lws_fragments frags[WSI_TOKEN_COUNT];
|
||||
time_t assigned;
|
||||
/*
|
||||
* for each recognized token, frag_index says which frag[] his data
|
||||
* starts in (0 means the token did not appear)
|
||||
* the actual header data gets dumped as it comes in, into data[]
|
||||
*/
|
||||
uint8_t frag_index[WSI_TOKEN_COUNT];
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
char initial_handshake_hash_base64[30];
|
||||
#endif
|
||||
|
||||
uint32_t pos;
|
||||
uint32_t http_response;
|
||||
uint32_t current_token_limit;
|
||||
int hdr_token_idx;
|
||||
|
||||
int16_t lextable_pos;
|
||||
|
||||
uint8_t in_use;
|
||||
uint8_t nfrag;
|
||||
char /*enum uri_path_states */ ups;
|
||||
char /*enum uri_esc_states */ ues;
|
||||
|
||||
char esc_stash;
|
||||
char post_literal_equal;
|
||||
uint8_t /* enum lws_token_indexes */ parser_state;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
struct lws_rewrite {
|
||||
hubbub_parser *parser;
|
||||
hubbub_parser_optparams params;
|
||||
const char *from, *to;
|
||||
int from_len, to_len;
|
||||
unsigned char *p, *end;
|
||||
struct lws *wsi;
|
||||
};
|
||||
static LWS_INLINE int hstrcmp(hubbub_string *s, const char *p, int len)
|
||||
{
|
||||
if ((int)s->len != len)
|
||||
return 1;
|
||||
|
||||
return strncmp((const char *)s->ptr, p, len);
|
||||
}
|
||||
typedef hubbub_error (*hubbub_callback_t)(const hubbub_token *token, void *pw);
|
||||
LWS_EXTERN struct lws_rewrite *
|
||||
lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to);
|
||||
LWS_EXTERN void
|
||||
lws_rewrite_destroy(struct lws_rewrite *r);
|
||||
LWS_EXTERN int
|
||||
lws_rewrite_parse(struct lws_rewrite *r, const unsigned char *in, int in_len);
|
||||
#endif
|
||||
|
||||
struct lws_pt_role_http {
|
||||
struct allocated_headers *ah_list;
|
||||
struct lws *ah_wait_list;
|
||||
#ifdef LWS_WITH_CGI
|
||||
struct lws_cgi *cgi_list;
|
||||
#endif
|
||||
int ah_wait_list_length;
|
||||
uint32_t ah_pool_length;
|
||||
|
||||
int ah_count_in_use;
|
||||
};
|
||||
|
||||
struct lws_peer_role_http {
|
||||
uint32_t count_ah;
|
||||
uint32_t total_ah;
|
||||
};
|
||||
|
||||
struct lws_vhost_role_http {
|
||||
char http_proxy_address[128];
|
||||
const struct lws_http_mount *mount_list;
|
||||
const char *error_document_404;
|
||||
unsigned int http_proxy_port;
|
||||
};
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
struct lws_access_log {
|
||||
char *header_log;
|
||||
char *user_agent;
|
||||
char *referrer;
|
||||
unsigned long sent;
|
||||
int response;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct _lws_http_mode_related {
|
||||
struct lws *new_wsi_list;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
struct lws_rewrite *rw;
|
||||
#endif
|
||||
struct allocated_headers *ah;
|
||||
struct lws *ah_wait_list;
|
||||
|
||||
lws_filepos_t filepos;
|
||||
lws_filepos_t filelen;
|
||||
lws_fop_fd_t fop_fd;
|
||||
|
||||
#if defined(LWS_WITH_RANGES)
|
||||
struct lws_range_parsing range;
|
||||
char multipart_content_type[64];
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
struct lws_access_log access_log;
|
||||
#endif
|
||||
#ifdef LWS_WITH_CGI
|
||||
struct lws_cgi *cgi; /* wsi being cgi master have one of these */
|
||||
#endif
|
||||
|
||||
enum http_version request_version;
|
||||
enum http_connection_type connection_type;
|
||||
lws_filepos_t tx_content_length;
|
||||
lws_filepos_t tx_content_remain;
|
||||
lws_filepos_t rx_content_length;
|
||||
lws_filepos_t rx_content_remain;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
unsigned int perform_rewrite:1;
|
||||
#endif
|
||||
unsigned int deferred_transaction_completed:1;
|
||||
};
|
||||
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
enum lws_chunk_parser {
|
||||
ELCP_HEX,
|
||||
ELCP_CR,
|
||||
ELCP_CONTENT,
|
||||
ELCP_POST_CR,
|
||||
ELCP_POST_LF,
|
||||
};
|
||||
#endif
|
||||
|
||||
enum lws_parse_urldecode_results {
|
||||
LPUR_CONTINUE,
|
||||
LPUR_SWALLOW,
|
||||
LPUR_FORBID,
|
||||
LPUR_EXCESSIVE,
|
||||
};
|
||||
|
||||
int
|
||||
lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
|
||||
|
||||
void
|
||||
_lws_header_table_reset(struct allocated_headers *ah);
|
||||
|
||||
LWS_EXTERN int
|
||||
_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah);
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - server access log handling
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
/*
|
||||
* Produce Apache-compatible log string for wsi, like this:
|
||||
*
|
||||
* 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]
|
||||
* "GET /aep-screen.png HTTP/1.1"
|
||||
* 200 152987 "https://libwebsockets.org/index.html"
|
||||
* "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36"
|
||||
*
|
||||
*/
|
||||
|
||||
extern const char * const method_names[];
|
||||
|
||||
static const char * const hver[] = {
|
||||
"HTTP/1.0", "HTTP/1.1", "HTTP/2"
|
||||
};
|
||||
|
||||
void
|
||||
lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int meth)
|
||||
{
|
||||
#ifdef LWS_WITH_IPV6
|
||||
char ads[INET6_ADDRSTRLEN];
|
||||
#else
|
||||
char ads[INET_ADDRSTRLEN];
|
||||
#endif
|
||||
char da[64];
|
||||
const char *pa, *me;
|
||||
struct tm *tmp;
|
||||
time_t t = time(NULL);
|
||||
int l = 256, m;
|
||||
|
||||
if (!wsi->vhost)
|
||||
return;
|
||||
|
||||
/* only worry about preparing it if we store it */
|
||||
if (wsi->vhost->log_fd == (int)LWS_INVALID_FILE)
|
||||
return;
|
||||
|
||||
if (wsi->access_log_pending)
|
||||
lws_access_log(wsi);
|
||||
|
||||
wsi->http.access_log.header_log = lws_malloc(l, "access log");
|
||||
if (wsi->http.access_log.header_log) {
|
||||
|
||||
tmp = localtime(&t);
|
||||
if (tmp)
|
||||
strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
|
||||
else
|
||||
strcpy(da, "01/Jan/1970:00:00:00 +0000");
|
||||
|
||||
pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
|
||||
if (!pa)
|
||||
pa = "(unknown)";
|
||||
|
||||
if (wsi->http2_substream)
|
||||
me = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
|
||||
else
|
||||
me = method_names[meth];
|
||||
if (!me)
|
||||
me = "(null)";
|
||||
|
||||
lws_snprintf(wsi->http.access_log.header_log, l,
|
||||
"%s - - [%s] \"%s %s %s\"",
|
||||
pa, da, me, uri_ptr,
|
||||
hver[wsi->http.request_version]);
|
||||
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
if (l) {
|
||||
wsi->http.access_log.user_agent = lws_malloc(l + 2, "access log");
|
||||
if (!wsi->http.access_log.user_agent) {
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
lws_free_set_NULL(wsi->http.access_log.header_log);
|
||||
return;
|
||||
}
|
||||
|
||||
lws_hdr_copy(wsi, wsi->http.access_log.user_agent,
|
||||
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->http.access_log.user_agent[m] == '\"')
|
||||
wsi->http.access_log.user_agent[m] = '\'';
|
||||
}
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);
|
||||
if (l) {
|
||||
wsi->http.access_log.referrer = lws_malloc(l + 2, "referrer");
|
||||
if (!wsi->http.access_log.referrer) {
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
lws_free_set_NULL(wsi->http.access_log.user_agent);
|
||||
lws_free_set_NULL(wsi->http.access_log.header_log);
|
||||
return;
|
||||
}
|
||||
lws_hdr_copy(wsi, wsi->http.access_log.referrer,
|
||||
l + 1, WSI_TOKEN_HTTP_REFERER);
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->http.access_log.referrer[m] == '\"')
|
||||
wsi->http.access_log.referrer[m] = '\'';
|
||||
}
|
||||
wsi->access_log_pending = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_access_log(struct lws *wsi)
|
||||
{
|
||||
char *p = wsi->http.access_log.user_agent, ass[512],
|
||||
*p1 = wsi->http.access_log.referrer;
|
||||
int l;
|
||||
|
||||
if (!wsi->vhost)
|
||||
return 0;
|
||||
|
||||
if (wsi->vhost->log_fd == (int)LWS_INVALID_FILE)
|
||||
return 0;
|
||||
|
||||
if (!wsi->access_log_pending)
|
||||
return 0;
|
||||
|
||||
if (!wsi->http.access_log.header_log)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
p = "";
|
||||
|
||||
if (!p1)
|
||||
p1 = "";
|
||||
|
||||
/*
|
||||
* We do this in two parts to restrict an oversize referrer such that
|
||||
* we will always have space left to append an empty useragent, while
|
||||
* maintaining the structure of the log text
|
||||
*/
|
||||
l = lws_snprintf(ass, sizeof(ass) - 7, "%s %d %lu \"%s",
|
||||
wsi->http.access_log.header_log,
|
||||
wsi->http.access_log.response, wsi->http.access_log.sent, p1);
|
||||
if (strlen(p) > sizeof(ass) - 6 - l)
|
||||
p[sizeof(ass) - 6 - l] = '\0';
|
||||
l += lws_snprintf(ass + l, sizeof(ass) - 1 - l, "\" \"%s\"\n", p);
|
||||
|
||||
if (write(wsi->vhost->log_fd, ass, l) != l)
|
||||
lwsl_err("Failed to write log\n");
|
||||
|
||||
if (wsi->http.access_log.header_log) {
|
||||
lws_free(wsi->http.access_log.header_log);
|
||||
wsi->http.access_log.header_log = NULL;
|
||||
}
|
||||
if (wsi->http.access_log.user_agent) {
|
||||
lws_free(wsi->http.access_log.user_agent);
|
||||
wsi->http.access_log.user_agent = NULL;
|
||||
}
|
||||
if (wsi->http.access_log.referrer) {
|
||||
lws_free(wsi->http.access_log.referrer);
|
||||
wsi->http.access_log.referrer = NULL;
|
||||
}
|
||||
wsi->access_log_pending = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,668 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Original code used in this source file:
|
||||
*
|
||||
* https://github.com/PerBothner/DomTerm.git @912add15f3d0aec
|
||||
*
|
||||
* ./lws-term/io.c
|
||||
* ./lws-term/junzip.c
|
||||
*
|
||||
* Copyright (C) 2017 Per Bothner <per@bothner.com>
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* lws rewrite:
|
||||
*
|
||||
* Copyright (C) 2017 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 "core/private.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
/*
|
||||
* This code works with zip format containers which may have files compressed
|
||||
* with gzip deflate (type 8) or store uncompressed (type 0).
|
||||
*
|
||||
* Linux zip produces such zipfiles by default, eg
|
||||
*
|
||||
* $ zip ../myzip.zip file1 file2 file3
|
||||
*/
|
||||
|
||||
#define ZIP_COMPRESSION_METHOD_STORE 0
|
||||
#define ZIP_COMPRESSION_METHOD_DEFLATE 8
|
||||
|
||||
typedef struct {
|
||||
lws_filepos_t filename_start;
|
||||
uint32_t crc32;
|
||||
uint32_t comp_size;
|
||||
uint32_t uncomp_size;
|
||||
uint32_t offset;
|
||||
uint32_t mod_time;
|
||||
uint16_t filename_len;
|
||||
uint16_t extra;
|
||||
uint16_t method;
|
||||
uint16_t file_com_len;
|
||||
} lws_fops_zip_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
struct lws_fop_fd fop_fd; /* MUST BE FIRST logical fop_fd into
|
||||
* file inside zip: fops_zip fops */
|
||||
lws_fop_fd_t zip_fop_fd; /* logical fop fd on to zip file
|
||||
* itself: using platform fops */
|
||||
lws_fops_zip_hdr_t hdr;
|
||||
z_stream inflate;
|
||||
lws_filepos_t content_start;
|
||||
lws_filepos_t exp_uncomp_pos;
|
||||
union {
|
||||
uint8_t trailer8[8];
|
||||
uint32_t trailer32[2];
|
||||
} u;
|
||||
uint8_t rbuf[128]; /* decompression chunk size */
|
||||
int entry_count;
|
||||
|
||||
unsigned int decompress:1; /* 0 = direct from file */
|
||||
unsigned int add_gzip_container:1;
|
||||
} *lws_fops_zip_t;
|
||||
|
||||
struct lws_plat_file_ops fops_zip;
|
||||
#define fop_fd_to_priv(FD) ((lws_fops_zip_t)(FD))
|
||||
|
||||
static const uint8_t hd[] = { 31, 139, 8, 0, 0, 0, 0, 0, 0, 3 };
|
||||
|
||||
enum {
|
||||
ZC_SIGNATURE = 0,
|
||||
ZC_VERSION_MADE_BY = 4,
|
||||
ZC_VERSION_NEEDED_TO_EXTRACT = 6,
|
||||
ZC_GENERAL_PURPOSE_BIT_FLAG = 8,
|
||||
ZC_COMPRESSION_METHOD = 10,
|
||||
ZC_LAST_MOD_FILE_TIME = 12,
|
||||
ZC_LAST_MOD_FILE_DATE = 14,
|
||||
ZC_CRC32 = 16,
|
||||
ZC_COMPRESSED_SIZE = 20,
|
||||
ZC_UNCOMPRESSED_SIZE = 24,
|
||||
ZC_FILE_NAME_LENGTH = 28,
|
||||
ZC_EXTRA_FIELD_LENGTH = 30,
|
||||
|
||||
ZC_FILE_COMMENT_LENGTH = 32,
|
||||
ZC_DISK_NUMBER_START = 34,
|
||||
ZC_INTERNAL_FILE_ATTRIBUTES = 36,
|
||||
ZC_EXTERNAL_FILE_ATTRIBUTES = 38,
|
||||
ZC_REL_OFFSET_LOCAL_HEADER = 42,
|
||||
ZC_DIRECTORY_LENGTH = 46,
|
||||
|
||||
ZE_SIGNATURE_OFFSET = 0,
|
||||
ZE_DESK_NUMBER = 4,
|
||||
ZE_CENTRAL_DIRECTORY_DISK_NUMBER = 6,
|
||||
ZE_NUM_ENTRIES_THIS_DISK = 8,
|
||||
ZE_NUM_ENTRIES = 10,
|
||||
ZE_CENTRAL_DIRECTORY_SIZE = 12,
|
||||
ZE_CENTRAL_DIR_OFFSET = 16,
|
||||
ZE_ZIP_COMMENT_LENGTH = 20,
|
||||
ZE_DIRECTORY_LENGTH = 22,
|
||||
|
||||
ZL_REL_OFFSET_CONTENT = 28,
|
||||
ZL_HEADER_LENGTH = 30,
|
||||
|
||||
LWS_FZ_ERR_SEEK_END_RECORD = 1,
|
||||
LWS_FZ_ERR_READ_END_RECORD,
|
||||
LWS_FZ_ERR_END_RECORD_MAGIC,
|
||||
LWS_FZ_ERR_END_RECORD_SANITY,
|
||||
LWS_FZ_ERR_CENTRAL_SEEK,
|
||||
LWS_FZ_ERR_CENTRAL_READ,
|
||||
LWS_FZ_ERR_CENTRAL_SANITY,
|
||||
LWS_FZ_ERR_NAME_TOO_LONG,
|
||||
LWS_FZ_ERR_NAME_SEEK,
|
||||
LWS_FZ_ERR_NAME_READ,
|
||||
LWS_FZ_ERR_CONTENT_SANITY,
|
||||
LWS_FZ_ERR_CONTENT_SEEK,
|
||||
LWS_FZ_ERR_SCAN_SEEK,
|
||||
LWS_FZ_ERR_NOT_FOUND,
|
||||
LWS_FZ_ERR_ZLIB_INIT,
|
||||
LWS_FZ_ERR_READ_CONTENT,
|
||||
LWS_FZ_ERR_SEEK_COMPRESSED,
|
||||
};
|
||||
|
||||
static uint16_t
|
||||
get_u16(void *p)
|
||||
{
|
||||
const uint8_t *c = (const uint8_t *)p;
|
||||
|
||||
return (uint16_t)((c[0] | (c[1] << 8)));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_u32(void *p)
|
||||
{
|
||||
const uint8_t *c = (const uint8_t *)p;
|
||||
|
||||
return (uint32_t)((c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)));
|
||||
}
|
||||
|
||||
int
|
||||
lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
|
||||
{
|
||||
lws_filepos_t amount;
|
||||
uint8_t buf[96];
|
||||
int i;
|
||||
|
||||
if (lws_vfs_file_seek_end(priv->zip_fop_fd, -ZE_DIRECTORY_LENGTH) < 0)
|
||||
return LWS_FZ_ERR_SEEK_END_RECORD;
|
||||
|
||||
if (lws_vfs_file_read(priv->zip_fop_fd, &amount, buf,
|
||||
ZE_DIRECTORY_LENGTH))
|
||||
return LWS_FZ_ERR_READ_END_RECORD;
|
||||
|
||||
if (amount != ZE_DIRECTORY_LENGTH)
|
||||
return LWS_FZ_ERR_READ_END_RECORD;
|
||||
|
||||
/*
|
||||
* We require the zip to have the last record right at the end
|
||||
* Linux zip always does this if no zip comment.
|
||||
*/
|
||||
if (buf[0] != 'P' || buf[1] != 'K' || buf[2] != 5 || buf[3] != 6)
|
||||
return LWS_FZ_ERR_END_RECORD_MAGIC;
|
||||
|
||||
i = get_u16(buf + ZE_NUM_ENTRIES);
|
||||
|
||||
if (get_u16(buf + ZE_DESK_NUMBER) ||
|
||||
get_u16(buf + ZE_CENTRAL_DIRECTORY_DISK_NUMBER) ||
|
||||
i != get_u16(buf + ZE_NUM_ENTRIES_THIS_DISK))
|
||||
return LWS_FZ_ERR_END_RECORD_SANITY;
|
||||
|
||||
/* end record is OK... look for our file in the central dir */
|
||||
|
||||
if (lws_vfs_file_seek_set(priv->zip_fop_fd,
|
||||
get_u32(buf + ZE_CENTRAL_DIR_OFFSET)) < 0)
|
||||
return LWS_FZ_ERR_CENTRAL_SEEK;
|
||||
|
||||
while (i--) {
|
||||
priv->content_start = lws_vfs_tell(priv->zip_fop_fd);
|
||||
|
||||
if (lws_vfs_file_read(priv->zip_fop_fd, &amount, buf,
|
||||
ZC_DIRECTORY_LENGTH))
|
||||
return LWS_FZ_ERR_CENTRAL_READ;
|
||||
|
||||
if (amount != ZC_DIRECTORY_LENGTH)
|
||||
return LWS_FZ_ERR_CENTRAL_READ;
|
||||
|
||||
if (get_u32(buf + ZC_SIGNATURE) != 0x02014B50)
|
||||
return LWS_FZ_ERR_CENTRAL_SANITY;
|
||||
|
||||
lwsl_debug("cstart 0x%lx\n", (unsigned long)priv->content_start);
|
||||
|
||||
priv->hdr.filename_len = get_u16(buf + ZC_FILE_NAME_LENGTH);
|
||||
priv->hdr.extra = get_u16(buf + ZC_EXTRA_FIELD_LENGTH);
|
||||
priv->hdr.filename_start = lws_vfs_tell(priv->zip_fop_fd);
|
||||
|
||||
priv->hdr.method = get_u16(buf + ZC_COMPRESSION_METHOD);
|
||||
priv->hdr.crc32 = get_u32(buf + ZC_CRC32);
|
||||
priv->hdr.comp_size = get_u32(buf + ZC_COMPRESSED_SIZE);
|
||||
priv->hdr.uncomp_size = get_u32(buf + ZC_UNCOMPRESSED_SIZE);
|
||||
priv->hdr.offset = get_u32(buf + ZC_REL_OFFSET_LOCAL_HEADER);
|
||||
priv->hdr.mod_time = get_u32(buf + ZC_LAST_MOD_FILE_TIME);
|
||||
priv->hdr.file_com_len = get_u16(buf + ZC_FILE_COMMENT_LENGTH);
|
||||
|
||||
if (priv->hdr.filename_len != len)
|
||||
goto next;
|
||||
|
||||
if (len >= (int)sizeof(buf) - 1)
|
||||
return LWS_FZ_ERR_NAME_TOO_LONG;
|
||||
|
||||
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
|
||||
&amount, buf, len))
|
||||
return LWS_FZ_ERR_NAME_READ;
|
||||
if ((int)amount != len)
|
||||
return LWS_FZ_ERR_NAME_READ;
|
||||
|
||||
buf[len] = '\0';
|
||||
lwsl_debug("check %s vs %s\n", buf, name);
|
||||
|
||||
if (strcmp((const char *)buf, name))
|
||||
goto next;
|
||||
|
||||
/* we found a match */
|
||||
if (lws_vfs_file_seek_set(priv->zip_fop_fd, priv->hdr.offset) < 0)
|
||||
return LWS_FZ_ERR_NAME_SEEK;
|
||||
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
|
||||
&amount, buf,
|
||||
ZL_HEADER_LENGTH))
|
||||
return LWS_FZ_ERR_NAME_READ;
|
||||
if (amount != ZL_HEADER_LENGTH)
|
||||
return LWS_FZ_ERR_NAME_READ;
|
||||
|
||||
priv->content_start = priv->hdr.offset +
|
||||
ZL_HEADER_LENGTH +
|
||||
priv->hdr.filename_len +
|
||||
get_u16(buf + ZL_REL_OFFSET_CONTENT);
|
||||
|
||||
lwsl_debug("content supposed to start at 0x%lx\n",
|
||||
(unsigned long)priv->content_start);
|
||||
|
||||
if (priv->content_start > priv->zip_fop_fd->len)
|
||||
return LWS_FZ_ERR_CONTENT_SANITY;
|
||||
|
||||
if (lws_vfs_file_seek_set(priv->zip_fop_fd,
|
||||
priv->content_start) < 0)
|
||||
return LWS_FZ_ERR_CONTENT_SEEK;
|
||||
|
||||
/* we are aligned at the start of the content */
|
||||
|
||||
priv->exp_uncomp_pos = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
next:
|
||||
if (i && lws_vfs_file_seek_set(priv->zip_fop_fd,
|
||||
priv->content_start +
|
||||
ZC_DIRECTORY_LENGTH +
|
||||
priv->hdr.filename_len +
|
||||
priv->hdr.extra +
|
||||
priv->hdr.file_com_len) < 0)
|
||||
return LWS_FZ_ERR_SCAN_SEEK;
|
||||
}
|
||||
|
||||
return LWS_FZ_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_fops_zip_reset_inflate(lws_fops_zip_t priv)
|
||||
{
|
||||
if (priv->decompress)
|
||||
inflateEnd(&priv->inflate);
|
||||
|
||||
priv->inflate.zalloc = Z_NULL;
|
||||
priv->inflate.zfree = Z_NULL;
|
||||
priv->inflate.opaque = Z_NULL;
|
||||
priv->inflate.avail_in = 0;
|
||||
priv->inflate.next_in = Z_NULL;
|
||||
|
||||
if (inflateInit2(&priv->inflate, -MAX_WBITS) != Z_OK) {
|
||||
lwsl_err("inflate init failed\n");
|
||||
return LWS_FZ_ERR_ZLIB_INIT;
|
||||
}
|
||||
|
||||
if (lws_vfs_file_seek_set(priv->zip_fop_fd, priv->content_start) < 0)
|
||||
return LWS_FZ_ERR_CONTENT_SEEK;
|
||||
|
||||
priv->exp_uncomp_pos = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lws_fop_fd_t
|
||||
lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
|
||||
const char *vpath, lws_fop_flags_t *flags)
|
||||
{
|
||||
lws_fop_flags_t local_flags = 0;
|
||||
lws_fops_zip_t priv;
|
||||
char rp[192];
|
||||
int m;
|
||||
|
||||
/*
|
||||
* vpath points at the / after the fops signature in vfs_path, eg
|
||||
* with a vfs_path "/var/www/docs/manual.zip/index.html", vpath
|
||||
* will come pointing at "/index.html"
|
||||
*/
|
||||
|
||||
priv = lws_zalloc(sizeof(*priv), "fops_zip priv");
|
||||
if (!priv)
|
||||
return NULL;
|
||||
|
||||
priv->fop_fd.fops = &fops_zip;
|
||||
|
||||
m = sizeof(rp) - 1;
|
||||
if ((vpath - vfs_path - 1) < m)
|
||||
m = lws_ptr_diff(vpath, vfs_path) - 1;
|
||||
lws_strncpy(rp, vfs_path, m + 1);
|
||||
|
||||
/* open the zip file itself using the incoming fops, not fops_zip */
|
||||
|
||||
priv->zip_fop_fd = fops->LWS_FOP_OPEN(fops, rp, NULL, &local_flags);
|
||||
if (!priv->zip_fop_fd) {
|
||||
lwsl_err("unable to open zip %s\n", rp);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
if (*vpath == '/')
|
||||
vpath++;
|
||||
|
||||
m = lws_fops_zip_scan(priv, vpath, (int)strlen(vpath));
|
||||
if (m) {
|
||||
lwsl_err("unable to find record matching '%s' %d\n", vpath, m);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/* the directory metadata tells us modification time, so pass it on */
|
||||
priv->fop_fd.mod_time = priv->hdr.mod_time;
|
||||
*flags |= LWS_FOP_FLAG_MOD_TIME_VALID | LWS_FOP_FLAG_VIRTUAL;
|
||||
priv->fop_fd.flags = *flags;
|
||||
|
||||
/* The zip fop_fd is left pointing at the start of the content.
|
||||
*
|
||||
* 1) Content could be uncompressed (STORE), and we can always serve
|
||||
* that directly
|
||||
*
|
||||
* 2) Content could be compressed (GZIP), and the client can handle
|
||||
* receiving GZIP... we can wrap it in a GZIP header and trailer
|
||||
* and serve the content part directly. The flag indicating we
|
||||
* are providing GZIP directly is set so lws will send the right
|
||||
* headers.
|
||||
*
|
||||
* 3) Content could be compressed (GZIP) but the client can't handle
|
||||
* receiving GZIP... we can decompress it and serve as it is
|
||||
* inflated piecemeal.
|
||||
*
|
||||
* 4) Content may be compressed some unknown way... fail
|
||||
*
|
||||
*/
|
||||
if (priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE) {
|
||||
/*
|
||||
* it is stored uncompressed, leave it indicated as
|
||||
* uncompressed, and just serve it from inside the
|
||||
* zip with no gzip container;
|
||||
*/
|
||||
|
||||
lwsl_info("direct zip serving (stored)\n");
|
||||
|
||||
priv->fop_fd.len = priv->hdr.uncomp_size;
|
||||
|
||||
return &priv->fop_fd;
|
||||
}
|
||||
|
||||
if ((*flags & LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP) &&
|
||||
priv->hdr.method == ZIP_COMPRESSION_METHOD_DEFLATE) {
|
||||
|
||||
/*
|
||||
* We can serve the gzipped file contents directly as gzip
|
||||
* from inside the zip container; client says it is OK.
|
||||
*
|
||||
* To convert to standalone gzip, we have to add a 10-byte
|
||||
* constant header and a variable 8-byte trailer around the
|
||||
* content.
|
||||
*
|
||||
* The 8-byte trailer is prepared now and held in the priv.
|
||||
*/
|
||||
|
||||
lwsl_info("direct zip serving (gzipped)\n");
|
||||
|
||||
priv->fop_fd.len = sizeof(hd) + priv->hdr.comp_size +
|
||||
sizeof(priv->u);
|
||||
|
||||
if (lws_is_be()) {
|
||||
uint8_t *p = priv->u.trailer8;
|
||||
|
||||
*p++ = (uint8_t)priv->hdr.crc32;
|
||||
*p++ = (uint8_t)(priv->hdr.crc32 >> 8);
|
||||
*p++ = (uint8_t)(priv->hdr.crc32 >> 16);
|
||||
*p++ = (uint8_t)(priv->hdr.crc32 >> 24);
|
||||
*p++ = (uint8_t)priv->hdr.uncomp_size;
|
||||
*p++ = (uint8_t)(priv->hdr.uncomp_size >> 8);
|
||||
*p++ = (uint8_t)(priv->hdr.uncomp_size >> 16);
|
||||
*p = (uint8_t)(priv->hdr.uncomp_size >> 24);
|
||||
} else {
|
||||
priv->u.trailer32[0] = priv->hdr.crc32;
|
||||
priv->u.trailer32[1] = priv->hdr.uncomp_size;
|
||||
}
|
||||
|
||||
*flags |= LWS_FOP_FLAG_COMPR_IS_GZIP;
|
||||
priv->fop_fd.flags = *flags;
|
||||
priv->add_gzip_container = 1;
|
||||
|
||||
return &priv->fop_fd;
|
||||
}
|
||||
|
||||
if (priv->hdr.method == ZIP_COMPRESSION_METHOD_DEFLATE) {
|
||||
|
||||
/* we must decompress it to serve it */
|
||||
|
||||
lwsl_info("decompressed zip serving\n");
|
||||
|
||||
priv->fop_fd.len = priv->hdr.uncomp_size;
|
||||
|
||||
if (lws_fops_zip_reset_inflate(priv)) {
|
||||
lwsl_err("inflate init failed\n");
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
priv->decompress = 1;
|
||||
|
||||
return &priv->fop_fd;
|
||||
}
|
||||
|
||||
/* we can't handle it ... */
|
||||
|
||||
lwsl_err("zipped file %s compressed in unknown way (%d)\n", vfs_path,
|
||||
priv->hdr.method);
|
||||
|
||||
bail2:
|
||||
lws_vfs_file_close(&priv->zip_fop_fd);
|
||||
bail1:
|
||||
free(priv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ie, we are closing the fop_fd for the file inside the gzip */
|
||||
|
||||
static int
|
||||
lws_fops_zip_close(lws_fop_fd_t *fd)
|
||||
{
|
||||
lws_fops_zip_t priv = fop_fd_to_priv(*fd);
|
||||
|
||||
if (priv->decompress)
|
||||
inflateEnd(&priv->inflate);
|
||||
|
||||
lws_vfs_file_close(&priv->zip_fop_fd); /* close the gzip fop_fd */
|
||||
|
||||
free(priv);
|
||||
*fd = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lws_fileofs_t
|
||||
lws_fops_zip_seek_cur(lws_fop_fd_t fd, lws_fileofs_t offset_from_cur_pos)
|
||||
{
|
||||
fd->pos += offset_from_cur_pos;
|
||||
|
||||
return fd->pos;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,
|
||||
lws_filepos_t len)
|
||||
{
|
||||
lws_fops_zip_t priv = fop_fd_to_priv(fd);
|
||||
lws_filepos_t ramount, rlen, cur = lws_vfs_tell(fd);
|
||||
int ret;
|
||||
|
||||
if (priv->decompress) {
|
||||
|
||||
if (priv->exp_uncomp_pos != fd->pos) {
|
||||
/*
|
||||
* there has been a seek in the uncompressed fop_fd
|
||||
* we have to restart the decompression and loop eating
|
||||
* the decompressed data up to the seek point
|
||||
*/
|
||||
lwsl_info("seek in decompressed\n");
|
||||
|
||||
lws_fops_zip_reset_inflate(priv);
|
||||
|
||||
while (priv->exp_uncomp_pos != fd->pos) {
|
||||
rlen = len;
|
||||
if (rlen > fd->pos - priv->exp_uncomp_pos)
|
||||
rlen = fd->pos - priv->exp_uncomp_pos;
|
||||
if (lws_fops_zip_read(fd, amount, buf, rlen))
|
||||
return LWS_FZ_ERR_SEEK_COMPRESSED;
|
||||
}
|
||||
*amount = 0;
|
||||
}
|
||||
|
||||
priv->inflate.avail_out = (unsigned int)len;
|
||||
priv->inflate.next_out = buf;
|
||||
|
||||
spin:
|
||||
if (!priv->inflate.avail_in) {
|
||||
rlen = sizeof(priv->rbuf);
|
||||
if (rlen > priv->hdr.comp_size -
|
||||
(cur - priv->content_start))
|
||||
rlen = priv->hdr.comp_size -
|
||||
(priv->hdr.comp_size -
|
||||
priv->content_start);
|
||||
|
||||
if (priv->zip_fop_fd->fops->LWS_FOP_READ(
|
||||
priv->zip_fop_fd, &ramount, priv->rbuf,
|
||||
rlen))
|
||||
return LWS_FZ_ERR_READ_CONTENT;
|
||||
|
||||
cur += ramount;
|
||||
|
||||
priv->inflate.avail_in = (unsigned int)ramount;
|
||||
priv->inflate.next_in = priv->rbuf;
|
||||
}
|
||||
|
||||
ret = inflate(&priv->inflate, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
return ret;
|
||||
|
||||
switch (ret) {
|
||||
case Z_NEED_DICT:
|
||||
ret = Z_DATA_ERROR;
|
||||
/* fallthru */
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!priv->inflate.avail_in && priv->inflate.avail_out &&
|
||||
cur != priv->content_start + priv->hdr.comp_size)
|
||||
goto spin;
|
||||
|
||||
*amount = len - priv->inflate.avail_out;
|
||||
|
||||
priv->exp_uncomp_pos += *amount;
|
||||
fd->pos += *amount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (priv->add_gzip_container) {
|
||||
|
||||
lwsl_info("%s: gzip + container\n", __func__);
|
||||
*amount = 0;
|
||||
|
||||
/* place the canned header at the start */
|
||||
|
||||
if (len && fd->pos < sizeof(hd)) {
|
||||
rlen = sizeof(hd) - fd->pos;
|
||||
if (rlen > len)
|
||||
rlen = len;
|
||||
/* provide stuff from canned header */
|
||||
memcpy(buf, hd + fd->pos, (size_t)rlen);
|
||||
fd->pos += rlen;
|
||||
buf += rlen;
|
||||
len -= rlen;
|
||||
*amount += rlen;
|
||||
}
|
||||
|
||||
/* serve gzipped data direct from zipfile */
|
||||
|
||||
if (len && fd->pos >= sizeof(hd) &&
|
||||
fd->pos < priv->hdr.comp_size + sizeof(hd)) {
|
||||
|
||||
rlen = priv->hdr.comp_size - (priv->zip_fop_fd->pos -
|
||||
priv->content_start);
|
||||
if (rlen > len)
|
||||
rlen = len;
|
||||
|
||||
if (rlen &&
|
||||
priv->zip_fop_fd->pos < (priv->hdr.comp_size +
|
||||
priv->content_start)) {
|
||||
if (lws_vfs_file_read(priv->zip_fop_fd,
|
||||
&ramount, buf, rlen))
|
||||
return LWS_FZ_ERR_READ_CONTENT;
|
||||
*amount += ramount;
|
||||
fd->pos += ramount; // virtual pos
|
||||
buf += ramount;
|
||||
len -= ramount;
|
||||
}
|
||||
}
|
||||
|
||||
/* place the prepared trailer at the end */
|
||||
|
||||
if (len && fd->pos >= priv->hdr.comp_size + sizeof(hd) &&
|
||||
fd->pos < priv->hdr.comp_size + sizeof(hd) +
|
||||
sizeof(priv->u)) {
|
||||
cur = fd->pos - priv->hdr.comp_size - sizeof(hd);
|
||||
rlen = sizeof(priv->u) - cur;
|
||||
if (rlen > len)
|
||||
rlen = len;
|
||||
|
||||
memcpy(buf, priv->u.trailer8 + cur, (size_t)rlen);
|
||||
|
||||
*amount += rlen;
|
||||
fd->pos += rlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_info("%s: store\n", __func__);
|
||||
|
||||
if (len > priv->hdr.uncomp_size - (cur - priv->content_start))
|
||||
len = priv->hdr.comp_size - (priv->hdr.comp_size -
|
||||
priv->content_start);
|
||||
|
||||
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
|
||||
amount, buf, len))
|
||||
return LWS_FZ_ERR_READ_CONTENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_plat_file_ops fops_zip = {
|
||||
lws_fops_zip_open,
|
||||
lws_fops_zip_close,
|
||||
lws_fops_zip_seek_cur,
|
||||
lws_fops_zip_read,
|
||||
NULL,
|
||||
{ { ".zip/", 5 }, { ".jar/", 5 }, { ".war/", 5 } },
|
||||
NULL,
|
||||
};
|
|
@ -1,993 +0,0 @@
|
|||
/*
|
||||
* libwebsockets web server application
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
/* this is needed for Travis CI */
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#define ESC_INSTALL_DATADIR "_lws_ddir_"
|
||||
|
||||
static const char * const paths_global[] = {
|
||||
"global.uid",
|
||||
"global.gid",
|
||||
"global.count-threads",
|
||||
"global.init-ssl",
|
||||
"global.server-string",
|
||||
"global.plugin-dir",
|
||||
"global.ws-pingpong-secs",
|
||||
"global.timeout-secs",
|
||||
"global.reject-service-keywords[].*",
|
||||
"global.reject-service-keywords[]",
|
||||
"global.default-alpn",
|
||||
};
|
||||
|
||||
enum lejp_global_paths {
|
||||
LEJPGP_UID,
|
||||
LEJPGP_GID,
|
||||
LEJPGP_COUNT_THREADS,
|
||||
LWJPGP_INIT_SSL,
|
||||
LEJPGP_SERVER_STRING,
|
||||
LEJPGP_PLUGIN_DIR,
|
||||
LWJPGP_PINGPONG_SECS,
|
||||
LWJPGP_TIMEOUT_SECS,
|
||||
LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
|
||||
LWJPGP_REJECT_SERVICE_KEYWORDS,
|
||||
LWJPGP_DEFAULT_ALPN,
|
||||
};
|
||||
|
||||
static const char * const paths_vhosts[] = {
|
||||
"vhosts[]",
|
||||
"vhosts[].mounts[]",
|
||||
"vhosts[].name",
|
||||
"vhosts[].port",
|
||||
"vhosts[].interface",
|
||||
"vhosts[].unix-socket",
|
||||
"vhosts[].sts",
|
||||
"vhosts[].host-ssl-key",
|
||||
"vhosts[].host-ssl-cert",
|
||||
"vhosts[].host-ssl-ca",
|
||||
"vhosts[].access-log",
|
||||
"vhosts[].mounts[].mountpoint",
|
||||
"vhosts[].mounts[].origin",
|
||||
"vhosts[].mounts[].protocol",
|
||||
"vhosts[].mounts[].default",
|
||||
"vhosts[].mounts[].auth-mask",
|
||||
"vhosts[].mounts[].cgi-timeout",
|
||||
"vhosts[].mounts[].cgi-env[].*",
|
||||
"vhosts[].mounts[].cache-max-age",
|
||||
"vhosts[].mounts[].cache-reuse",
|
||||
"vhosts[].mounts[].cache-revalidate",
|
||||
"vhosts[].mounts[].basic-auth",
|
||||
"vhosts[].mounts[].cache-intermediaries",
|
||||
"vhosts[].mounts[].extra-mimetypes.*",
|
||||
"vhosts[].mounts[].interpret.*",
|
||||
"vhosts[].ws-protocols[].*.*",
|
||||
"vhosts[].ws-protocols[].*",
|
||||
"vhosts[].ws-protocols[]",
|
||||
"vhosts[].keepalive_timeout",
|
||||
"vhosts[].enable-client-ssl",
|
||||
"vhosts[].ciphers",
|
||||
"vhosts[].ecdh-curve",
|
||||
"vhosts[].noipv6",
|
||||
"vhosts[].ipv6only",
|
||||
"vhosts[].ssl-option-set",
|
||||
"vhosts[].ssl-option-clear",
|
||||
"vhosts[].mounts[].pmo[].*",
|
||||
"vhosts[].headers[].*",
|
||||
"vhosts[].headers[]",
|
||||
"vhosts[].client-ssl-key",
|
||||
"vhosts[].client-ssl-cert",
|
||||
"vhosts[].client-ssl-ca",
|
||||
"vhosts[].client-ssl-ciphers",
|
||||
"vhosts[].onlyraw",
|
||||
"vhosts[].client-cert-required",
|
||||
"vhosts[].ignore-missing-cert",
|
||||
"vhosts[].error-document-404",
|
||||
"vhosts[].alpn",
|
||||
};
|
||||
|
||||
enum lejp_vhost_paths {
|
||||
LEJPVP,
|
||||
LEJPVP_MOUNTS,
|
||||
LEJPVP_NAME,
|
||||
LEJPVP_PORT,
|
||||
LEJPVP_INTERFACE,
|
||||
LEJPVP_UNIXSKT,
|
||||
LEJPVP_STS,
|
||||
LEJPVP_HOST_SSL_KEY,
|
||||
LEJPVP_HOST_SSL_CERT,
|
||||
LEJPVP_HOST_SSL_CA,
|
||||
LEJPVP_ACCESS_LOG,
|
||||
LEJPVP_MOUNTPOINT,
|
||||
LEJPVP_ORIGIN,
|
||||
LEJPVP_MOUNT_PROTOCOL,
|
||||
LEJPVP_DEFAULT,
|
||||
LEJPVP_DEFAULT_AUTH_MASK,
|
||||
LEJPVP_CGI_TIMEOUT,
|
||||
LEJPVP_CGI_ENV,
|
||||
LEJPVP_MOUNT_CACHE_MAX_AGE,
|
||||
LEJPVP_MOUNT_CACHE_REUSE,
|
||||
LEJPVP_MOUNT_CACHE_REVALIDATE,
|
||||
LEJPVP_MOUNT_BASIC_AUTH,
|
||||
LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
|
||||
LEJPVP_MOUNT_EXTRA_MIMETYPES,
|
||||
LEJPVP_MOUNT_INTERPRET,
|
||||
LEJPVP_PROTOCOL_NAME_OPT,
|
||||
LEJPVP_PROTOCOL_NAME,
|
||||
LEJPVP_PROTOCOL,
|
||||
LEJPVP_KEEPALIVE_TIMEOUT,
|
||||
LEJPVP_ENABLE_CLIENT_SSL,
|
||||
LEJPVP_CIPHERS,
|
||||
LEJPVP_ECDH_CURVE,
|
||||
LEJPVP_NOIPV6,
|
||||
LEJPVP_IPV6ONLY,
|
||||
LEJPVP_SSL_OPTION_SET,
|
||||
LEJPVP_SSL_OPTION_CLEAR,
|
||||
LEJPVP_PMO,
|
||||
LEJPVP_HEADERS_NAME,
|
||||
LEJPVP_HEADERS,
|
||||
LEJPVP_CLIENT_SSL_KEY,
|
||||
LEJPVP_CLIENT_SSL_CERT,
|
||||
LEJPVP_CLIENT_SSL_CA,
|
||||
LEJPVP_CLIENT_CIPHERS,
|
||||
LEJPVP_FLAG_ONLYRAW,
|
||||
LEJPVP_FLAG_CLIENT_CERT_REQUIRED,
|
||||
LEJPVP_IGNORE_MISSING_CERT,
|
||||
LEJPVP_ERROR_DOCUMENT_404,
|
||||
LEJPVP_ALPN,
|
||||
};
|
||||
|
||||
static const char * const parser_errs[] = {
|
||||
"",
|
||||
"",
|
||||
"No opening '{'",
|
||||
"Expected closing '}'",
|
||||
"Expected '\"'",
|
||||
"String underrun",
|
||||
"Illegal unescaped control char",
|
||||
"Illegal escape format",
|
||||
"Illegal hex number",
|
||||
"Expected ':'",
|
||||
"Illegal value start",
|
||||
"Digit required after decimal point",
|
||||
"Bad number format",
|
||||
"Bad exponent format",
|
||||
"Unknown token",
|
||||
"Too many ']'",
|
||||
"Mismatched ']'",
|
||||
"Expected ']'",
|
||||
"JSON nesting limit exceeded",
|
||||
"Nesting tracking used up",
|
||||
"Number too long",
|
||||
"Comma or block end expected",
|
||||
"Unknown",
|
||||
"Parser callback errored (see earlier error)",
|
||||
};
|
||||
|
||||
#define MAX_PLUGIN_DIRS 10
|
||||
|
||||
struct jpargs {
|
||||
struct lws_context_creation_info *info;
|
||||
struct lws_context *context;
|
||||
const struct lws_protocols *protocols;
|
||||
const struct lws_extension *extensions;
|
||||
char *p, *end, valid;
|
||||
struct lws_http_mount *head, *last;
|
||||
|
||||
struct lws_protocol_vhost_options *pvo;
|
||||
struct lws_protocol_vhost_options *pvo_em;
|
||||
struct lws_protocol_vhost_options *pvo_int;
|
||||
struct lws_http_mount m;
|
||||
const char **plugin_dirs;
|
||||
int count_plugin_dirs;
|
||||
|
||||
unsigned int enable_client_ssl:1;
|
||||
unsigned int fresh_mount:1;
|
||||
unsigned int any_vhosts:1;
|
||||
unsigned int chunk:1;
|
||||
};
|
||||
|
||||
static void *
|
||||
lwsws_align(struct jpargs *a)
|
||||
{
|
||||
if ((lws_intptr_t)(a->p) & 15)
|
||||
a->p += 16 - ((lws_intptr_t)(a->p) & 15);
|
||||
|
||||
a->chunk = 0;
|
||||
|
||||
return a->p;
|
||||
}
|
||||
|
||||
static int
|
||||
arg_to_bool(const char *s)
|
||||
{
|
||||
static const char * const on[] = { "on", "yes", "true" };
|
||||
int n = atoi(s);
|
||||
|
||||
if (n)
|
||||
return 1;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(on); n++)
|
||||
if (!strcasecmp(s, on[n]))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static signed char
|
||||
lejp_globals_cb(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
struct jpargs *a = (struct jpargs *)ctx->user;
|
||||
struct lws_protocol_vhost_options *rej;
|
||||
int n;
|
||||
|
||||
/* we only match on the prepared path strings */
|
||||
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
|
||||
return 0;
|
||||
|
||||
/* this catches, eg, vhosts[].headers[].xxx */
|
||||
if (reason == LEJPCB_VAL_STR_END &&
|
||||
ctx->path_match == LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {
|
||||
rej = lwsws_align(a);
|
||||
a->p += sizeof(*rej);
|
||||
|
||||
n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
|
||||
rej->next = a->info->reject_service_keywords;
|
||||
a->info->reject_service_keywords = rej;
|
||||
rej->name = a->p;
|
||||
lwsl_notice(" adding rej %s=%s\n", a->p, ctx->buf);
|
||||
a->p += n - 1;
|
||||
*(a->p++) = '\0';
|
||||
rej->value = a->p;
|
||||
rej->options = NULL;
|
||||
goto dostring;
|
||||
}
|
||||
|
||||
switch (ctx->path_match - 1) {
|
||||
case LEJPGP_UID:
|
||||
a->info->uid = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LEJPGP_GID:
|
||||
a->info->gid = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LEJPGP_COUNT_THREADS:
|
||||
a->info->count_threads = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LWJPGP_INIT_SSL:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
return 0;
|
||||
case LEJPGP_SERVER_STRING:
|
||||
a->info->server_string = a->p;
|
||||
break;
|
||||
case LEJPGP_PLUGIN_DIR:
|
||||
if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
|
||||
lwsl_err("Too many plugin dirs\n");
|
||||
return -1;
|
||||
}
|
||||
a->plugin_dirs[a->count_plugin_dirs++] = a->p;
|
||||
break;
|
||||
|
||||
case LWJPGP_PINGPONG_SECS:
|
||||
a->info->ws_ping_pong_interval = atoi(ctx->buf);
|
||||
return 0;
|
||||
|
||||
case LWJPGP_TIMEOUT_SECS:
|
||||
a->info->timeout_secs = atoi(ctx->buf);
|
||||
return 0;
|
||||
|
||||
case LWJPGP_DEFAULT_ALPN:
|
||||
a->info->alpn = a->p;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
dostring:
|
||||
a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
|
||||
*(a->p)++ = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static signed char
|
||||
lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
struct jpargs *a = (struct jpargs *)ctx->user;
|
||||
struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
|
||||
struct lws_http_mount *m;
|
||||
char *p, *p1;
|
||||
int n;
|
||||
|
||||
#if 0
|
||||
lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
|
||||
for (n = 0; n < ctx->wildcount; n++)
|
||||
lwsl_notice(" %d\n", ctx->wild[n]);
|
||||
#endif
|
||||
|
||||
if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
|
||||
uint32_t i[4];
|
||||
const char *ss;
|
||||
|
||||
/* set the defaults for this vhost */
|
||||
a->valid = 1;
|
||||
a->head = NULL;
|
||||
a->last = NULL;
|
||||
|
||||
i[0] = a->info->count_threads;
|
||||
i[1] = a->info->options & (
|
||||
LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME |
|
||||
LWS_SERVER_OPTION_LIBUV |
|
||||
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
|
||||
LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN |
|
||||
LWS_SERVER_OPTION_LIBEVENT |
|
||||
LWS_SERVER_OPTION_LIBEV
|
||||
);
|
||||
ss = a->info->server_string;
|
||||
i[2] = a->info->ws_ping_pong_interval;
|
||||
i[3] = a->info->timeout_secs;
|
||||
|
||||
memset(a->info, 0, sizeof(*a->info));
|
||||
|
||||
a->info->count_threads = i[0];
|
||||
a->info->options = i[1];
|
||||
a->info->server_string = ss;
|
||||
a->info->ws_ping_pong_interval = i[2];
|
||||
a->info->timeout_secs = i[3];
|
||||
|
||||
a->info->protocols = a->protocols;
|
||||
a->info->extensions = a->extensions;
|
||||
#if defined(LWS_WITH_TLS)
|
||||
a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:"
|
||||
"DHE-RSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-RSA-AES256-SHA384:"
|
||||
"HIGH:!aNULL:!eNULL:!EXPORT:"
|
||||
"!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
|
||||
"!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
|
||||
"!DHE-RSA-AES128-SHA256:"
|
||||
"!AES128-GCM-SHA256:"
|
||||
"!AES128-SHA256:"
|
||||
"!DHE-RSA-AES256-SHA256:"
|
||||
"!AES256-GCM-SHA384:"
|
||||
"!AES256-SHA256";
|
||||
#endif
|
||||
a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:"
|
||||
"DHE-RSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-RSA-AES256-SHA384:"
|
||||
"HIGH:!aNULL:!eNULL:!EXPORT:"
|
||||
"!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
|
||||
"!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
|
||||
"!DHE-RSA-AES128-SHA256:"
|
||||
"!AES128-GCM-SHA256:"
|
||||
"!AES128-SHA256:"
|
||||
"!DHE-RSA-AES256-SHA256:"
|
||||
"!AES256-GCM-SHA384:"
|
||||
"!AES256-SHA256";
|
||||
a->info->keepalive_timeout = 5;
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_OBJECT_START &&
|
||||
ctx->path_match == LEJPVP_MOUNTS + 1) {
|
||||
a->fresh_mount = 1;
|
||||
memset(&a->m, 0, sizeof(a->m));
|
||||
}
|
||||
|
||||
/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
|
||||
if (reason == LEJPCB_OBJECT_START &&
|
||||
ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
|
||||
a->pvo = lwsws_align(a);
|
||||
a->p += sizeof(*a->pvo);
|
||||
|
||||
n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
|
||||
/* ie, enable this protocol, no options yet */
|
||||
a->pvo->next = a->info->pvo;
|
||||
a->info->pvo = a->pvo;
|
||||
a->pvo->name = a->p;
|
||||
lwsl_info(" adding protocol %s\n", a->p);
|
||||
a->p += n;
|
||||
a->pvo->value = a->p;
|
||||
a->pvo->options = NULL;
|
||||
goto dostring;
|
||||
}
|
||||
|
||||
/* this catches, eg, vhosts[].headers[].xxx */
|
||||
if ((reason == LEJPCB_VAL_STR_END || reason == LEJPCB_VAL_STR_CHUNK) &&
|
||||
ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
|
||||
if (!a->chunk) {
|
||||
headers = lwsws_align(a);
|
||||
a->p += sizeof(*headers);
|
||||
|
||||
n = lejp_get_wildcard(ctx, 0, a->p,
|
||||
lws_ptr_diff(a->end, a->p));
|
||||
/* ie, add this header */
|
||||
headers->next = a->info->headers;
|
||||
a->info->headers = headers;
|
||||
headers->name = a->p;
|
||||
|
||||
lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
|
||||
a->p += n - 1;
|
||||
*(a->p++) = ':';
|
||||
if (a->p < a->end)
|
||||
*(a->p++) = '\0';
|
||||
else
|
||||
*(a->p - 1) = '\0';
|
||||
headers->value = a->p;
|
||||
headers->options = NULL;
|
||||
}
|
||||
a->chunk = reason == LEJPCB_VAL_STR_CHUNK;
|
||||
goto dostring;
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_OBJECT_END &&
|
||||
(ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
|
||||
a->valid) {
|
||||
|
||||
struct lws_vhost *vhost;
|
||||
|
||||
//lwsl_notice("%s\n", ctx->path);
|
||||
if (!a->info->port) {
|
||||
lwsl_err("Port required (eg, 443)");
|
||||
return 1;
|
||||
}
|
||||
a->valid = 0;
|
||||
a->info->mounts = a->head;
|
||||
|
||||
vhost = lws_create_vhost(a->context, a->info);
|
||||
if (!vhost) {
|
||||
lwsl_err("Failed to create vhost %s\n",
|
||||
a->info->vhost_name);
|
||||
return 1;
|
||||
}
|
||||
a->any_vhosts = 1;
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (a->enable_client_ssl) {
|
||||
const char *cert_filepath = a->info->client_ssl_cert_filepath;
|
||||
const char *private_key_filepath = a->info->client_ssl_private_key_filepath;
|
||||
const char *ca_filepath = a->info->client_ssl_ca_filepath;
|
||||
const char *cipher_list = a->info->client_ssl_cipher_list;
|
||||
memset(a->info, 0, sizeof(*a->info));
|
||||
a->info->client_ssl_cert_filepath = cert_filepath;
|
||||
a->info->client_ssl_private_key_filepath = private_key_filepath;
|
||||
a->info->client_ssl_ca_filepath = ca_filepath;
|
||||
a->info->client_ssl_cipher_list = cipher_list;
|
||||
a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
lws_init_vhost_client_ssl(a->info, vhost);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_OBJECT_END &&
|
||||
ctx->path_match == LEJPVP_MOUNTS + 1) {
|
||||
static const char * const mount_protocols[] = {
|
||||
"http://",
|
||||
"https://",
|
||||
"file://",
|
||||
"cgi://",
|
||||
">http://",
|
||||
">https://",
|
||||
"callback://",
|
||||
"gzip://",
|
||||
};
|
||||
|
||||
if (!a->fresh_mount)
|
||||
return 0;
|
||||
|
||||
if (!a->m.mountpoint || !a->m.origin) {
|
||||
lwsl_err("mountpoint and origin required\n");
|
||||
return 1;
|
||||
}
|
||||
lwsl_debug("adding mount %s\n", a->m.mountpoint);
|
||||
m = lwsws_align(a);
|
||||
memcpy(m, &a->m, sizeof(*m));
|
||||
if (a->last)
|
||||
a->last->mount_next = m;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(mount_protocols); n++)
|
||||
if (!strncmp(a->m.origin, mount_protocols[n],
|
||||
strlen(mount_protocols[n]))) {
|
||||
lwsl_info("----%s\n", a->m.origin);
|
||||
m->origin_protocol = n;
|
||||
m->origin = a->m.origin +
|
||||
strlen(mount_protocols[n]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == (int)LWS_ARRAY_SIZE(mount_protocols)) {
|
||||
lwsl_err("unsupported protocol:// %s\n", a->m.origin);
|
||||
return 1;
|
||||
}
|
||||
|
||||
a->p += sizeof(*m);
|
||||
if (!a->head)
|
||||
a->head = m;
|
||||
|
||||
a->last = m;
|
||||
a->fresh_mount = 0;
|
||||
}
|
||||
|
||||
/* we only match on the prepared path strings */
|
||||
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
|
||||
return 0;
|
||||
|
||||
switch (ctx->path_match - 1) {
|
||||
case LEJPVP_NAME:
|
||||
a->info->vhost_name = a->p;
|
||||
break;
|
||||
case LEJPVP_PORT:
|
||||
a->info->port = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_INTERFACE:
|
||||
a->info->iface = a->p;
|
||||
break;
|
||||
case LEJPVP_UNIXSKT:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
|
||||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
|
||||
return 0;
|
||||
case LEJPVP_STS:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_STS;
|
||||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_STS);
|
||||
return 0;
|
||||
case LEJPVP_HOST_SSL_KEY:
|
||||
a->info->ssl_private_key_filepath = a->p;
|
||||
break;
|
||||
case LEJPVP_HOST_SSL_CERT:
|
||||
a->info->ssl_cert_filepath = a->p;
|
||||
break;
|
||||
case LEJPVP_HOST_SSL_CA:
|
||||
a->info->ssl_ca_filepath = a->p;
|
||||
break;
|
||||
case LEJPVP_ACCESS_LOG:
|
||||
a->info->log_filepath = a->p;
|
||||
break;
|
||||
case LEJPVP_MOUNTPOINT:
|
||||
a->m.mountpoint = a->p;
|
||||
a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
|
||||
break;
|
||||
case LEJPVP_ORIGIN:
|
||||
if (!strncmp(ctx->buf, "callback://", 11))
|
||||
a->m.protocol = a->p + 11;
|
||||
|
||||
if (!a->m.origin)
|
||||
a->m.origin = a->p;
|
||||
break;
|
||||
case LEJPVP_DEFAULT:
|
||||
a->m.def = a->p;
|
||||
break;
|
||||
case LEJPVP_DEFAULT_AUTH_MASK:
|
||||
a->m.auth_mask = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_MOUNT_CACHE_MAX_AGE:
|
||||
a->m.cache_max_age = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_MOUNT_CACHE_REUSE:
|
||||
a->m.cache_reusable = arg_to_bool(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_MOUNT_CACHE_REVALIDATE:
|
||||
a->m.cache_revalidate = arg_to_bool(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
|
||||
a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
|
||||
return 0;
|
||||
case LEJPVP_MOUNT_BASIC_AUTH:
|
||||
a->m.basic_auth_login_file = a->p;
|
||||
break;
|
||||
case LEJPVP_CGI_TIMEOUT:
|
||||
a->m.cgi_timeout = atoi(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_KEEPALIVE_TIMEOUT:
|
||||
a->info->keepalive_timeout = atoi(ctx->buf);
|
||||
return 0;
|
||||
#if defined(LWS_WITH_TLS)
|
||||
case LEJPVP_CLIENT_CIPHERS:
|
||||
a->info->client_ssl_cipher_list = a->p;
|
||||
break;
|
||||
#endif
|
||||
case LEJPVP_CIPHERS:
|
||||
a->info->ssl_cipher_list = a->p;
|
||||
break;
|
||||
case LEJPVP_ECDH_CURVE:
|
||||
a->info->ecdh_curve = a->p;
|
||||
break;
|
||||
case LEJPVP_PMO:
|
||||
case LEJPVP_CGI_ENV:
|
||||
mp_cgienv = lwsws_align(a);
|
||||
a->p += sizeof(*a->m.cgienv);
|
||||
|
||||
mp_cgienv->next = a->m.cgienv;
|
||||
a->m.cgienv = mp_cgienv;
|
||||
|
||||
n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
|
||||
mp_cgienv->name = a->p;
|
||||
a->p += n;
|
||||
mp_cgienv->value = a->p;
|
||||
mp_cgienv->options = NULL;
|
||||
//lwsl_notice(" adding pmo / cgi-env '%s' = '%s'\n", mp_cgienv->name,
|
||||
// mp_cgienv->value);
|
||||
goto dostring;
|
||||
|
||||
case LEJPVP_PROTOCOL_NAME_OPT:
|
||||
/* this catches, eg,
|
||||
* vhosts[].ws-protocols[].xxx-protocol.yyy-option
|
||||
* ie, these are options attached to a protocol with { }
|
||||
*/
|
||||
pvo = lwsws_align(a);
|
||||
a->p += sizeof(*a->pvo);
|
||||
|
||||
n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
|
||||
/* ie, enable this protocol, no options yet */
|
||||
pvo->next = a->pvo->options;
|
||||
a->pvo->options = pvo;
|
||||
pvo->name = a->p;
|
||||
a->p += n;
|
||||
pvo->value = a->p;
|
||||
pvo->options = NULL;
|
||||
break;
|
||||
|
||||
case LEJPVP_MOUNT_EXTRA_MIMETYPES:
|
||||
a->pvo_em = lwsws_align(a);
|
||||
a->p += sizeof(*a->pvo_em);
|
||||
|
||||
n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
|
||||
/* ie, enable this protocol, no options yet */
|
||||
a->pvo_em->next = a->m.extra_mimetypes;
|
||||
a->m.extra_mimetypes = a->pvo_em;
|
||||
a->pvo_em->name = a->p;
|
||||
lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
|
||||
a->p += n;
|
||||
a->pvo_em->value = a->p;
|
||||
a->pvo_em->options = NULL;
|
||||
break;
|
||||
|
||||
case LEJPVP_MOUNT_INTERPRET:
|
||||
a->pvo_int = lwsws_align(a);
|
||||
a->p += sizeof(*a->pvo_int);
|
||||
|
||||
n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
|
||||
/* ie, enable this protocol, no options yet */
|
||||
a->pvo_int->next = a->m.interpret;
|
||||
a->m.interpret = a->pvo_int;
|
||||
a->pvo_int->name = a->p;
|
||||
lwsl_notice(" adding interpret %s -> %s\n", a->p,
|
||||
ctx->buf);
|
||||
a->p += n;
|
||||
a->pvo_int->value = a->p;
|
||||
a->pvo_int->options = NULL;
|
||||
break;
|
||||
|
||||
case LEJPVP_ENABLE_CLIENT_SSL:
|
||||
a->enable_client_ssl = arg_to_bool(ctx->buf);
|
||||
return 0;
|
||||
#if defined(LWS_WITH_TLS)
|
||||
case LEJPVP_CLIENT_SSL_KEY:
|
||||
a->info->client_ssl_private_key_filepath = a->p;
|
||||
break;
|
||||
case LEJPVP_CLIENT_SSL_CERT:
|
||||
a->info->client_ssl_cert_filepath = a->p;
|
||||
break;
|
||||
case LEJPVP_CLIENT_SSL_CA:
|
||||
a->info->client_ssl_ca_filepath = a->p;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LEJPVP_NOIPV6:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
|
||||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
|
||||
return 0;
|
||||
|
||||
case LEJPVP_FLAG_ONLYRAW:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_ONLY_RAW;
|
||||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_ONLY_RAW);
|
||||
return 0;
|
||||
|
||||
case LEJPVP_IPV6ONLY:
|
||||
a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;
|
||||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
|
||||
return 0;
|
||||
|
||||
case LEJPVP_FLAG_CLIENT_CERT_REQUIRED:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |=
|
||||
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
|
||||
return 0;
|
||||
|
||||
case LEJPVP_IGNORE_MISSING_CERT:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
|
||||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_IGNORE_MISSING_CERT);
|
||||
|
||||
return 0;
|
||||
|
||||
case LEJPVP_ERROR_DOCUMENT_404:
|
||||
a->info->error_document_404 = a->p;
|
||||
break;
|
||||
|
||||
case LEJPVP_SSL_OPTION_SET:
|
||||
a->info->ssl_options_set |= atol(ctx->buf);
|
||||
return 0;
|
||||
case LEJPVP_SSL_OPTION_CLEAR:
|
||||
a->info->ssl_options_clear |= atol(ctx->buf);
|
||||
return 0;
|
||||
|
||||
case LEJPVP_ALPN:
|
||||
a->info->alpn = a->p;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
dostring:
|
||||
p = ctx->buf;
|
||||
p[LEJP_STRING_CHUNK] = '\0';
|
||||
p1 = strstr(p, ESC_INSTALL_DATADIR);
|
||||
if (p1) {
|
||||
n = p1 - p;
|
||||
if (n > a->end - a->p)
|
||||
n = a->end - a->p;
|
||||
lws_strncpy(a->p, p, n + 1);
|
||||
a->p += n;
|
||||
a->p += lws_snprintf(a->p, a->end - a->p, "%s", LWS_INSTALL_DATADIR);
|
||||
p += n + strlen(ESC_INSTALL_DATADIR);
|
||||
}
|
||||
|
||||
a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
|
||||
if (reason == LEJPCB_VAL_STR_END)
|
||||
*(a->p)++ = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 0 = OK, 1 = can't open, 2 = parsing error
|
||||
*/
|
||||
|
||||
static int
|
||||
lwsws_get_config(void *user, const char *f, const char * const *paths,
|
||||
int count_paths, lejp_callback cb)
|
||||
{
|
||||
unsigned char buf[128];
|
||||
struct lejp_ctx ctx;
|
||||
int n, m, fd;
|
||||
|
||||
fd = lws_open(f, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
lwsl_err("Cannot open %s\n", f);
|
||||
return 2;
|
||||
}
|
||||
lwsl_info("%s: %s\n", __func__, f);
|
||||
lejp_construct(&ctx, cb, user, paths, count_paths);
|
||||
|
||||
do {
|
||||
n = read(fd, buf, sizeof(buf));
|
||||
if (!n)
|
||||
break;
|
||||
|
||||
m = (int)(signed char)lejp_parse(&ctx, buf, n);
|
||||
} while (m == LEJP_CONTINUE);
|
||||
|
||||
close(fd);
|
||||
n = ctx.line;
|
||||
lejp_destruct(&ctx);
|
||||
|
||||
if (m < 0) {
|
||||
lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
|
||||
parser_errs[-m]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_LIBUV) && UV_VERSION_MAJOR > 0
|
||||
|
||||
static int
|
||||
lwsws_get_config_d(void *user, const char *d, const char * const *paths,
|
||||
int count_paths, lejp_callback cb)
|
||||
{
|
||||
uv_dirent_t dent;
|
||||
uv_fs_t req;
|
||||
char path[256];
|
||||
int ret = 0, ir;
|
||||
uv_loop_t loop;
|
||||
|
||||
ir = uv_loop_init(&loop);
|
||||
if (ir) {
|
||||
lwsl_err("%s: loop init failed %d\n", __func__, ir);
|
||||
}
|
||||
|
||||
if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
|
||||
lwsl_err("Scandir on %s failed\n", d);
|
||||
return 2;
|
||||
}
|
||||
|
||||
while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
|
||||
lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
|
||||
ret = lwsws_get_config(user, path, paths, count_paths, cb);
|
||||
if (ret)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
bail:
|
||||
uv_fs_req_cleanup(&req);
|
||||
while (uv_loop_close(&loop))
|
||||
;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifndef _WIN32
|
||||
static int filter(const struct dirent *ent)
|
||||
{
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lwsws_get_config_d(void *user, const char *d, const char * const *paths,
|
||||
int count_paths, lejp_callback cb)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct dirent **namelist;
|
||||
char path[256];
|
||||
int n, i, ret = 0;
|
||||
|
||||
n = scandir(d, &namelist, filter, alphasort);
|
||||
if (n < 0) {
|
||||
lwsl_err("Scandir on %s failed\n", d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strchr(namelist[i]->d_name, '~'))
|
||||
goto skip;
|
||||
lws_snprintf(path, sizeof(path) - 1, "%s/%s", d,
|
||||
namelist[i]->d_name);
|
||||
ret = lwsws_get_config(user, path, paths, count_paths, cb);
|
||||
if (ret) {
|
||||
while (i++ < n)
|
||||
free(namelist[i]);
|
||||
goto bail;
|
||||
}
|
||||
skip:
|
||||
free(namelist[i]);
|
||||
}
|
||||
|
||||
bail:
|
||||
free(namelist);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
|
||||
char **cs, int *len)
|
||||
{
|
||||
struct jpargs a;
|
||||
const char * const *old = info->plugin_dirs;
|
||||
char dd[128];
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
|
||||
a.info = info;
|
||||
a.p = *cs;
|
||||
a.end = (a.p + *len) - 1;
|
||||
a.valid = 0;
|
||||
|
||||
lwsws_align(&a);
|
||||
info->plugin_dirs = (void *)a.p;
|
||||
a.plugin_dirs = (void *)a.p; /* writeable version */
|
||||
a.p += MAX_PLUGIN_DIRS * sizeof(void *);
|
||||
|
||||
/* copy any default paths */
|
||||
|
||||
while (old && *old) {
|
||||
a.plugin_dirs[a.count_plugin_dirs++] = *old;
|
||||
old++;
|
||||
}
|
||||
|
||||
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
|
||||
if (lwsws_get_config(&a, dd, paths_global,
|
||||
LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
|
||||
return 1;
|
||||
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
|
||||
if (lwsws_get_config_d(&a, dd, paths_global,
|
||||
LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
|
||||
return 1;
|
||||
|
||||
a.plugin_dirs[a.count_plugin_dirs] = NULL;
|
||||
|
||||
*cs = a.p;
|
||||
*len = a.end - a.p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lwsws_get_config_vhosts(struct lws_context *context,
|
||||
struct lws_context_creation_info *info, const char *d,
|
||||
char **cs, int *len)
|
||||
{
|
||||
struct jpargs a;
|
||||
char dd[128];
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
|
||||
a.info = info;
|
||||
a.p = *cs;
|
||||
a.end = a.p + *len;
|
||||
a.valid = 0;
|
||||
a.context = context;
|
||||
a.protocols = info->protocols;
|
||||
a.extensions = info->extensions;
|
||||
|
||||
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
|
||||
if (lwsws_get_config(&a, dd, paths_vhosts,
|
||||
LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
|
||||
return 1;
|
||||
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
|
||||
if (lwsws_get_config_d(&a, dd, paths_vhosts,
|
||||
LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
|
||||
return 1;
|
||||
|
||||
*cs = a.p;
|
||||
*len = a.end - a.p;
|
||||
|
||||
if (!a.any_vhosts) {
|
||||
lwsl_err("Need at least one vhost\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// lws_finalize_startup(context);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 <core/private.h>
|
||||
|
||||
static int
|
||||
rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_pollfd *pollfd)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
|
||||
lws_sock_file_fd_type fd;
|
||||
int opts = LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;
|
||||
struct sockaddr_storage cli_addr;
|
||||
socklen_t clilen;
|
||||
|
||||
/* pollin means a client has connected to us then
|
||||
*
|
||||
* pollout is a hack on esp32 for background accepts signalling
|
||||
* they completed
|
||||
*/
|
||||
|
||||
do {
|
||||
struct lws *cwsi;
|
||||
|
||||
if (!(pollfd->revents & (LWS_POLLIN | LWS_POLLOUT)) ||
|
||||
!(pollfd->events & LWS_POLLIN))
|
||||
break;
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
/*
|
||||
* can we really accept it, with regards to SSL limit?
|
||||
* another vhost may also have had POLLIN on his
|
||||
* listener this round and used it up already
|
||||
*/
|
||||
if (wsi->vhost->tls.use_ssl &&
|
||||
context->simultaneous_ssl_restriction &&
|
||||
context->simultaneous_ssl ==
|
||||
context->simultaneous_ssl_restriction)
|
||||
/*
|
||||
* no... ignore it, he won't come again until
|
||||
* we are below the simultaneous_ssl_restriction
|
||||
* limit and POLLIN is enabled on him again
|
||||
*/
|
||||
break;
|
||||
#endif
|
||||
/* listen socket got an unencrypted connection... */
|
||||
|
||||
clilen = sizeof(cli_addr);
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
/*
|
||||
* We cannot identify the peer who is in the listen
|
||||
* socket connect queue before we accept it; even if
|
||||
* we could, not accepting it due to PEER_LIMITS would
|
||||
* block the connect queue for other legit peers.
|
||||
*/
|
||||
|
||||
accept_fd = accept((int)pollfd->fd,
|
||||
(struct sockaddr *)&cli_addr, &clilen);
|
||||
lws_latency(context, wsi, "listener accept",
|
||||
(int)accept_fd, accept_fd != LWS_SOCK_INVALID);
|
||||
if (accept_fd == LWS_SOCK_INVALID) {
|
||||
if (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK) {
|
||||
break;
|
||||
}
|
||||
lwsl_err("ERROR on accept: %s\n",
|
||||
strerror(LWS_ERRNO));
|
||||
break;
|
||||
}
|
||||
|
||||
lws_plat_set_socket_options(wsi->vhost, accept_fd);
|
||||
|
||||
#if defined(LWS_WITH_IPV6)
|
||||
lwsl_debug("accepted new conn port %u on fd=%d\n",
|
||||
((cli_addr.ss_family == AF_INET6) ?
|
||||
ntohs(((struct sockaddr_in6 *) &cli_addr)->sin6_port) :
|
||||
ntohs(((struct sockaddr_in *) &cli_addr)->sin_port)),
|
||||
accept_fd);
|
||||
#else
|
||||
lwsl_debug("accepted new conn port %u on fd=%d\n",
|
||||
ntohs(((struct sockaddr_in *) &cli_addr)->sin_port),
|
||||
accept_fd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* look at who we connected to and give user code a
|
||||
* chance to reject based on client IP. There's no
|
||||
* protocol selected yet so we issue this to
|
||||
* protocols[0]
|
||||
*/
|
||||
if ((wsi->vhost->protocols[0].callback)(wsi,
|
||||
LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
|
||||
NULL,
|
||||
(void *)(lws_intptr_t)accept_fd, 0)) {
|
||||
lwsl_debug("Callback denied net connection\n");
|
||||
compatible_close(accept_fd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(wsi->vhost->options & LWS_SERVER_OPTION_ONLY_RAW))
|
||||
opts |= LWS_ADOPT_HTTP;
|
||||
else
|
||||
opts = LWS_ADOPT_SOCKET;
|
||||
|
||||
fd.sockfd = accept_fd;
|
||||
cwsi = lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
|
||||
NULL, NULL);
|
||||
if (!cwsi)
|
||||
/* already closed cleanly as necessary */
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
|
||||
if (lws_server_socket_service_ssl(cwsi, accept_fd)) {
|
||||
lws_close_free_wsi(cwsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"listen svc fail");
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
}
|
||||
|
||||
lwsl_info("%s: new wsi %p: wsistate 0x%x, role_ops %s\n",
|
||||
__func__, cwsi, cwsi->wsistate, cwsi->role_ops->name);
|
||||
|
||||
} while (pt->fds_count < context->fd_limit_per_thread - 1 &&
|
||||
wsi->position_in_fds_table != LWS_NO_FDS_POS &&
|
||||
lws_poll_listen_fd(&pt->fds[wsi->position_in_fds_table]) > 0);
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
int rops_handle_POLLOUT_listen(struct lws *wsi)
|
||||
{
|
||||
return LWS_HP_RET_USER_SERVICE;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_listen = {
|
||||
/* role name */ "listen",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_listen,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_listen,
|
||||
/* perform_user_POLLOUT */ NULL,
|
||||
/* callback_on_writable */ NULL,
|
||||
/* tx_credit */ NULL,
|
||||
/* write_role_protocol */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
/* close cb clnt, srv */ { 0, 0 },
|
||||
/* file_handle */ 0,
|
||||
};
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 <core/private.h>
|
||||
|
||||
static int
|
||||
rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_pollfd *pollfd)
|
||||
{
|
||||
#if !defined(WIN32) && !defined(_WIN32)
|
||||
char s[100];
|
||||
int n;
|
||||
|
||||
/*
|
||||
* discard the byte(s) that signaled us
|
||||
* We really don't care about the number of bytes, but coverity
|
||||
* thinks we should.
|
||||
*/
|
||||
n = read(wsi->desc.sockfd, s, sizeof(s));
|
||||
(void)n;
|
||||
if (n < 0)
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
#endif
|
||||
/*
|
||||
* the poll() wait, or the event loop for libuv etc is a
|
||||
* process-wide resource that we interrupted. So let every
|
||||
* protocol that may be interested in the pipe event know that
|
||||
* it happened.
|
||||
*/
|
||||
if (lws_broadcast(wsi->context, LWS_CALLBACK_EVENT_WAIT_CANCELLED,
|
||||
NULL, 0)) {
|
||||
lwsl_info("closed in event cancel\n");
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
}
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_pipe = {
|
||||
/* role name */ "pipe",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_pipe,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
/* perform_user_POLLOUT */ NULL,
|
||||
/* callback_on_writable */ NULL,
|
||||
/* tx_credit */ NULL,
|
||||
/* write_role_protocol */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
/* close cb clnt, srv */ { 0, 0 },
|
||||
/* file_handle */ 1,
|
||||
};
|
|
@ -1,282 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h
|
||||
*/
|
||||
|
||||
typedef uint32_t lws_wsi_state_t;
|
||||
|
||||
/*
|
||||
* The wsi->role_ops pointer decides almost everything about what role the wsi
|
||||
* will play, h2, raw, ws, etc.
|
||||
*
|
||||
* However there are a few additional flags needed that vary, such as if the
|
||||
* role is a client or server side, if it has that concept. And the connection
|
||||
* fulfilling the role, has a separate dynamic state.
|
||||
*
|
||||
* 31 16 15 0
|
||||
* [ role flags ] [ state ]
|
||||
*
|
||||
* The role flags part is generally invariant for the lifetime of the wsi,
|
||||
* although it can change if the connection role itself does, eg, if the
|
||||
* connection upgrades from H1 -> WS1 the role flags may be changed at that
|
||||
* point.
|
||||
*
|
||||
* The state part reflects the dynamic connection state, and the states are
|
||||
* reused between roles.
|
||||
*
|
||||
* None of the internal role or state representations are made available outside
|
||||
* of lws internals. Even for lws internals, if you add stuff here, please keep
|
||||
* the constants inside this header only by adding necessary helpers here and
|
||||
* use the helpers in the actual code. This is to ease any future refactors.
|
||||
*
|
||||
* Notice LWSIFR_ENCAP means we have a parent wsi that actually carries our
|
||||
* data as a stream inside a different protocol.
|
||||
*/
|
||||
|
||||
#define _RS 16
|
||||
|
||||
#define LWSIFR_CLIENT (0x1000 << _RS) /* client side */
|
||||
#define LWSIFR_SERVER (0x2000 << _RS) /* server side */
|
||||
|
||||
#define LWSIFR_P_ENCAP_H2 (0x0100 << _RS) /* we are encapsulated by h2 */
|
||||
|
||||
enum lwsi_role {
|
||||
LWSI_ROLE_MASK = (0xffff << _RS),
|
||||
LWSI_ROLE_ENCAP_MASK = (0x0f00 << _RS),
|
||||
};
|
||||
|
||||
#define lwsi_role(wsi) (wsi->wsistate & LWSI_ROLE_MASK)
|
||||
#if !defined (_DEBUG)
|
||||
#define lwsi_set_role(wsi, role) wsi->wsistate = \
|
||||
(wsi->wsistate & (~LWSI_ROLE_MASK)) | role
|
||||
#else
|
||||
void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role);
|
||||
#endif
|
||||
|
||||
#define lwsi_role_client(wsi) (!!(wsi->wsistate & LWSIFR_CLIENT))
|
||||
#define lwsi_role_server(wsi) (!!(wsi->wsistate & LWSIFR_SERVER))
|
||||
#define lwsi_role_h2_ENCAPSULATION(wsi) \
|
||||
((wsi->wsistate & LWSI_ROLE_ENCAP_MASK) == LWSIFR_P_ENCAP_H2)
|
||||
|
||||
/* Pollout wants a callback in this state */
|
||||
#define LWSIFS_POCB (0x100)
|
||||
/* Before any protocol connection was established */
|
||||
#define LWSIFS_NOT_EST (0x200)
|
||||
|
||||
enum lwsi_state {
|
||||
|
||||
/* Phase 1: pre-transport */
|
||||
|
||||
LRS_UNCONNECTED = LWSIFS_NOT_EST | 0,
|
||||
LRS_WAITING_CONNECT = LWSIFS_NOT_EST | 1,
|
||||
|
||||
/* Phase 2: establishing intermediaries on top of transport */
|
||||
|
||||
LRS_WAITING_PROXY_REPLY = LWSIFS_NOT_EST | 2,
|
||||
LRS_WAITING_SSL = LWSIFS_NOT_EST | 3,
|
||||
LRS_WAITING_SOCKS_GREETING_REPLY = LWSIFS_NOT_EST | 4,
|
||||
LRS_WAITING_SOCKS_CONNECT_REPLY = LWSIFS_NOT_EST | 5,
|
||||
LRS_WAITING_SOCKS_AUTH_REPLY = LWSIFS_NOT_EST | 6,
|
||||
|
||||
/* Phase 3: establishing tls tunnel */
|
||||
|
||||
LRS_SSL_INIT = LWSIFS_NOT_EST | 7,
|
||||
LRS_SSL_ACK_PENDING = LWSIFS_NOT_EST | 8,
|
||||
LRS_PRE_WS_SERVING_ACCEPT = LWSIFS_NOT_EST | 9,
|
||||
|
||||
/* Phase 4: connected */
|
||||
|
||||
LRS_WAITING_SERVER_REPLY = LWSIFS_NOT_EST | 10,
|
||||
LRS_H2_AWAIT_PREFACE = LWSIFS_NOT_EST | 11,
|
||||
LRS_H2_AWAIT_SETTINGS = LWSIFS_NOT_EST |
|
||||
LWSIFS_POCB | 12,
|
||||
|
||||
/* Phase 5: protocol logically established */
|
||||
|
||||
LRS_H2_CLIENT_SEND_SETTINGS = LWSIFS_POCB | 13,
|
||||
LRS_H2_WAITING_TO_SEND_HEADERS = LWSIFS_POCB | 14,
|
||||
LRS_DEFERRING_ACTION = LWSIFS_POCB | 15,
|
||||
LRS_IDLING = 16,
|
||||
LRS_H1C_ISSUE_HANDSHAKE = 17,
|
||||
LRS_H1C_ISSUE_HANDSHAKE2 = 18,
|
||||
LRS_ISSUE_HTTP_BODY = 19,
|
||||
LRS_ISSUING_FILE = 20,
|
||||
LRS_HEADERS = 21,
|
||||
LRS_BODY = 22,
|
||||
LRS_ESTABLISHED = LWSIFS_POCB | 23,
|
||||
/* we are established, but we have embarked on serving a single
|
||||
* transaction. Other transaction input may be pending, but we will
|
||||
* not service it while we are busy dealing with the current
|
||||
* transaction.
|
||||
*
|
||||
* When we complete the current transaction, we would reset our state
|
||||
* back to ESTABLISHED and start to process the next transaction.
|
||||
*/
|
||||
LRS_DOING_TRANSACTION = LWSIFS_POCB | 24,
|
||||
|
||||
/* Phase 6: finishing */
|
||||
|
||||
LRS_WAITING_TO_SEND_CLOSE = LWSIFS_POCB | 25,
|
||||
LRS_RETURNED_CLOSE = LWSIFS_POCB | 26,
|
||||
LRS_AWAITING_CLOSE_ACK = LWSIFS_POCB | 27,
|
||||
LRS_FLUSHING_BEFORE_CLOSE = LWSIFS_POCB | 28,
|
||||
LRS_SHUTDOWN = 29,
|
||||
|
||||
/* Phase 7: dead */
|
||||
|
||||
LRS_DEAD_SOCKET = 30,
|
||||
|
||||
LRS_MASK = 0xffff
|
||||
};
|
||||
|
||||
#define lwsi_state(wsi) ((enum lwsi_state)(wsi->wsistate & LRS_MASK))
|
||||
#define lwsi_state_PRE_CLOSE(wsi) ((enum lwsi_state)(wsi->wsistate_pre_close & LRS_MASK))
|
||||
#define lwsi_state_est(wsi) (!(wsi->wsistate & LWSIFS_NOT_EST))
|
||||
#define lwsi_state_est_PRE_CLOSE(wsi) (!(wsi->wsistate_pre_close & LWSIFS_NOT_EST))
|
||||
#define lwsi_state_can_handle_POLLOUT(wsi) (wsi->wsistate & LWSIFS_POCB)
|
||||
#if !defined (_DEBUG)
|
||||
#define lwsi_set_state(wsi, lrs) wsi->wsistate = \
|
||||
(wsi->wsistate & (~LRS_MASK)) | lrs
|
||||
#else
|
||||
void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* internal role-specific ops
|
||||
*/
|
||||
struct lws_context_per_thread;
|
||||
struct lws_role_ops {
|
||||
const char *name;
|
||||
const char *alpn;
|
||||
/*
|
||||
* After http headers have parsed, this is the last chance for a role
|
||||
* to upgrade the connection to something else using the headers.
|
||||
* ws-over-h2 is upgraded from h2 like this.
|
||||
*/
|
||||
int (*check_upgrades)(struct lws *wsi);
|
||||
/* role-specific context init during context creation */
|
||||
int (*init_context)(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info);
|
||||
/* role-specific per-vhost init during vhost creation */
|
||||
int (*init_vhost)(struct lws_vhost *vh,
|
||||
const struct lws_context_creation_info *info);
|
||||
/* role-specific per-vhost destructor during vhost destroy */
|
||||
int (*destroy_vhost)(struct lws_vhost *vh);
|
||||
/* generic 1Hz callback for the role itself */
|
||||
int (*periodic_checks)(struct lws_context *context, int tsi,
|
||||
time_t now);
|
||||
/* chance for the role to force POLLIN without network activity */
|
||||
int (*service_flag_pending)(struct lws_context *context, int tsi);
|
||||
/* an fd using this role has POLLIN signalled */
|
||||
int (*handle_POLLIN)(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_pollfd *pollfd);
|
||||
/* an fd using the role wanted a POLLOUT callback and now has it */
|
||||
int (*handle_POLLOUT)(struct lws *wsi);
|
||||
/* perform user pollout */
|
||||
int (*perform_user_POLLOUT)(struct lws *wsi);
|
||||
/* do effective callback on writeable */
|
||||
int (*callback_on_writable)(struct lws *wsi);
|
||||
/* connection-specific tx credit in bytes */
|
||||
lws_fileofs_t (*tx_credit)(struct lws *wsi);
|
||||
/* role-specific write formatting */
|
||||
int (*write_role_protocol)(struct lws *wsi, unsigned char *buf,
|
||||
size_t len, enum lws_write_protocol *wp);
|
||||
|
||||
/* get encapsulation parent */
|
||||
struct lws * (*encapsulation_parent)(struct lws *wsi);
|
||||
|
||||
/* role-specific destructor */
|
||||
int (*alpn_negotiated)(struct lws *wsi, const char *alpn);
|
||||
|
||||
/* chance for the role to handle close in the protocol */
|
||||
int (*close_via_role_protocol)(struct lws *wsi,
|
||||
enum lws_close_status reason);
|
||||
/* role-specific close processing */
|
||||
int (*close_role)(struct lws_context_per_thread *pt, struct lws *wsi);
|
||||
/* role-specific connection close processing */
|
||||
int (*close_kill_connection)(struct lws *wsi,
|
||||
enum lws_close_status reason);
|
||||
/* role-specific destructor */
|
||||
int (*destroy_role)(struct lws *wsi);
|
||||
|
||||
/*
|
||||
* the callback reasons for WRITEABLE for client, server
|
||||
* (just client applies if no concept of client or server)
|
||||
*/
|
||||
uint16_t writeable_cb[2];
|
||||
/*
|
||||
* the callback reasons for CLOSE for client, server
|
||||
* (just client applies if no concept of client or server)
|
||||
*/
|
||||
uint16_t close_cb[2];
|
||||
|
||||
unsigned int file_handle:1; /* role operates on files not sockets */
|
||||
};
|
||||
|
||||
/* core roles */
|
||||
extern struct lws_role_ops role_ops_raw_skt, role_ops_raw_file, role_ops_listen,
|
||||
role_ops_pipe;
|
||||
|
||||
/* bring in role private declarations */
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
#include "roles/http/private.h"
|
||||
#else
|
||||
#define lwsi_role_http(wsi) (0)
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_H1)
|
||||
#include "roles/h1/private.h"
|
||||
#else
|
||||
#define lwsi_role_h1(wsi) (0)
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_H2)
|
||||
#include "roles/h2/private.h"
|
||||
#else
|
||||
#define lwsi_role_h2(wsi) (0)
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_WS)
|
||||
#include "roles/ws/private.h"
|
||||
#else
|
||||
#define lwsi_role_ws(wsi) (0)
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_CGI)
|
||||
#include "roles/cgi/private.h"
|
||||
#else
|
||||
#define lwsi_role_cgi(wsi) (0)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
LWS_HP_RET_BAIL_OK,
|
||||
LWS_HP_RET_BAIL_DIE,
|
||||
LWS_HP_RET_USER_SERVICE,
|
||||
|
||||
LWS_HPI_RET_WSI_ALREADY_DIED, /* we closed it */
|
||||
LWS_HPI_RET_HANDLED, /* no probs */
|
||||
LWS_HPI_RET_PLEASE_CLOSE_ME, /* close it for us */
|
||||
|
||||
LWS_UPG_RET_DONE,
|
||||
LWS_UPG_RET_CONTINUE,
|
||||
LWS_UPG_RET_BAIL
|
||||
};
|
|
@ -1,223 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 <core/private.h>
|
||||
|
||||
static int
|
||||
rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_pollfd *pollfd)
|
||||
{
|
||||
struct lws_tokens ebuf;
|
||||
int n, buffered;
|
||||
|
||||
/* pending truncated sends have uber priority */
|
||||
|
||||
if (wsi->trunc_len) {
|
||||
if (!(pollfd->revents & LWS_POLLOUT))
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset,
|
||||
wsi->trunc_len) < 0)
|
||||
goto fail;
|
||||
/*
|
||||
* we can't afford to allow input processing to send
|
||||
* something new, so spin around he event loop until
|
||||
* he doesn't have any partials
|
||||
*/
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
if ((pollfd->revents & pollfd->events & LWS_POLLIN) &&
|
||||
/* any tunnel has to have been established... */
|
||||
lwsi_state(wsi) != LRS_SSL_ACK_PENDING &&
|
||||
!(wsi->favoured_pollin &&
|
||||
(pollfd->revents & pollfd->events & LWS_POLLOUT))) {
|
||||
|
||||
buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
|
||||
switch (ebuf.len) {
|
||||
case 0:
|
||||
lwsl_info("%s: read 0 len\n", __func__);
|
||||
wsi->seen_zero_length_recv = 1;
|
||||
lws_change_pollfd(wsi, LWS_POLLIN, 0);
|
||||
|
||||
/*
|
||||
* we need to go to fail here, since it's the only
|
||||
* chance we get to understand that the socket has
|
||||
* closed
|
||||
*/
|
||||
// goto try_pollout;
|
||||
goto fail;
|
||||
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto fail;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
n = user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RAW_RX,
|
||||
wsi->user_space, ebuf.token,
|
||||
ebuf.len);
|
||||
if (n < 0) {
|
||||
lwsl_info("LWS_CALLBACK_RAW_RX_fail\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lws_buflist_aware_consume(wsi, &ebuf, ebuf.len, buffered))
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
} else
|
||||
if (wsi->favoured_pollin &&
|
||||
(pollfd->revents & pollfd->events & LWS_POLLOUT))
|
||||
/* we balanced the last favouring of pollin */
|
||||
wsi->favoured_pollin = 0;
|
||||
|
||||
try_pollout:
|
||||
|
||||
/* this handles POLLOUT for http serving fragments */
|
||||
|
||||
if (!(pollfd->revents & LWS_POLLOUT))
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
/* one shot */
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_notice("%s a\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* clear back-to-back write detection */
|
||||
wsi->could_have_pending = 0;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_WRITEABLE_CB, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (wsi->active_writable_req_us) {
|
||||
uint64_t ul = time_in_microseconds() -
|
||||
wsi->active_writable_req_us;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_MS_WRITABLE_DELAY, ul);
|
||||
lws_stats_atomic_max(wsi->context, pt,
|
||||
LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
|
||||
wsi->active_writable_req_us = 0;
|
||||
}
|
||||
#endif
|
||||
n = user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RAW_WRITEABLE,
|
||||
wsi->user_space, NULL, 0);
|
||||
if (n < 0) {
|
||||
lwsl_info("writeable_fail\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
fail:
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "raw svc fail");
|
||||
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rops_handle_POLLIN_raw_file(struct lws_context_per_thread *pt, struct lws *wsi,
|
||||
struct lws_pollfd *pollfd)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (pollfd->revents & LWS_POLLOUT) {
|
||||
n = lws_callback_as_writeable(wsi);
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
}
|
||||
if (n)
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
}
|
||||
|
||||
if (pollfd->revents & LWS_POLLIN) {
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RAW_RX_FILE,
|
||||
wsi->user_space, NULL, 0)) {
|
||||
lwsl_debug("raw rx callback closed it\n");
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
}
|
||||
}
|
||||
|
||||
if (pollfd->revents & LWS_POLLHUP)
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
struct lws_role_ops role_ops_raw_skt = {
|
||||
/* role name */ "raw-skt",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_raw_skt,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
/* perform_user_POLLOUT */ NULL,
|
||||
/* callback_on_writable */ NULL,
|
||||
/* tx_credit */ NULL,
|
||||
/* write_role_protocol */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE, 0 },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE, 0 },
|
||||
/* file_handle */ 0,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct lws_role_ops role_ops_raw_file = {
|
||||
/* role name */ "raw-file",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_raw_file,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
/* perform_user_POLLOUT */ NULL,
|
||||
/* callback_on_writable */ NULL,
|
||||
/* tx_credit */ NULL,
|
||||
/* write_role_protocol */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE_FILE, 0 },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE_FILE, 0 },
|
||||
/* file_handle */ 1,
|
||||
};
|
|
@ -1,605 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
/*
|
||||
* parsers.c: lws_ws_rx_sm() needs to be roughly kept in
|
||||
* sync with changes here, esp related to ext draining
|
||||
*/
|
||||
|
||||
int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
|
||||
{
|
||||
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
|
||||
int handled, m;
|
||||
unsigned short close_code;
|
||||
struct lws_tokens ebuf;
|
||||
unsigned char *pp;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
int rx_draining_ext = 0, n;
|
||||
#endif
|
||||
|
||||
ebuf.token = NULL;
|
||||
ebuf.len = 0;
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (wsi->ws->rx_draining_ext) {
|
||||
assert(!c);
|
||||
|
||||
lws_remove_wsi_from_draining_ext_list(wsi);
|
||||
rx_draining_ext = 1;
|
||||
lwsl_debug("%s: doing draining flow\n", __func__);
|
||||
|
||||
goto drain_extension;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsi->socket_is_permanently_unusable)
|
||||
return -1;
|
||||
|
||||
switch (wsi->lws_rx_parse_state) {
|
||||
case LWS_RXPS_NEW:
|
||||
/* control frames (PING) may interrupt checkable sequences */
|
||||
wsi->ws->defeat_check_utf8 = 0;
|
||||
|
||||
switch (wsi->ws->ietf_spec_revision) {
|
||||
case 13:
|
||||
wsi->ws->opcode = c & 0xf;
|
||||
/* revisit if an extension wants them... */
|
||||
switch (wsi->ws->opcode) {
|
||||
case LWSWSOPC_TEXT_FRAME:
|
||||
wsi->ws->rsv_first_msg = (c & 0x70);
|
||||
wsi->ws->continuation_possible = 1;
|
||||
wsi->ws->check_utf8 = lws_check_opt(
|
||||
wsi->context->options,
|
||||
LWS_SERVER_OPTION_VALIDATE_UTF8);
|
||||
wsi->ws->utf8 = 0;
|
||||
wsi->ws->first_fragment = 1;
|
||||
break;
|
||||
case LWSWSOPC_BINARY_FRAME:
|
||||
wsi->ws->rsv_first_msg = (c & 0x70);
|
||||
wsi->ws->check_utf8 = 0;
|
||||
wsi->ws->continuation_possible = 1;
|
||||
wsi->ws->first_fragment = 1;
|
||||
break;
|
||||
case LWSWSOPC_CONTINUATION:
|
||||
if (!wsi->ws->continuation_possible) {
|
||||
lwsl_info("disordered continuation\n");
|
||||
return -1;
|
||||
}
|
||||
wsi->ws->first_fragment = 0;
|
||||
break;
|
||||
case LWSWSOPC_CLOSE:
|
||||
wsi->ws->check_utf8 = 0;
|
||||
wsi->ws->utf8 = 0;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 0xb:
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
case 0xf:
|
||||
lwsl_info("illegal opcode\n");
|
||||
return -1;
|
||||
default:
|
||||
wsi->ws->defeat_check_utf8 = 1;
|
||||
break;
|
||||
}
|
||||
wsi->ws->rsv = (c & 0x70);
|
||||
/* revisit if an extension wants them... */
|
||||
if (
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
!wsi->ws->count_act_ext &&
|
||||
#endif
|
||||
wsi->ws->rsv) {
|
||||
lwsl_info("illegal rsv bits set\n");
|
||||
return -1;
|
||||
}
|
||||
wsi->ws->final = !!((c >> 7) & 1);
|
||||
lwsl_ext("%s: This RX frame Final %d\n", __func__,
|
||||
wsi->ws->final);
|
||||
|
||||
if (wsi->ws->owed_a_fin &&
|
||||
(wsi->ws->opcode == LWSWSOPC_TEXT_FRAME ||
|
||||
wsi->ws->opcode == LWSWSOPC_BINARY_FRAME)) {
|
||||
lwsl_info("hey you owed us a FIN\n");
|
||||
return -1;
|
||||
}
|
||||
if ((!(wsi->ws->opcode & 8)) && wsi->ws->final) {
|
||||
wsi->ws->continuation_possible = 0;
|
||||
wsi->ws->owed_a_fin = 0;
|
||||
}
|
||||
|
||||
if ((wsi->ws->opcode & 8) && !wsi->ws->final) {
|
||||
lwsl_info("control msg can't be fragmented\n");
|
||||
return -1;
|
||||
}
|
||||
if (!wsi->ws->final)
|
||||
wsi->ws->owed_a_fin = 1;
|
||||
|
||||
switch (wsi->ws->opcode) {
|
||||
case LWSWSOPC_TEXT_FRAME:
|
||||
case LWSWSOPC_BINARY_FRAME:
|
||||
wsi->ws->frame_is_binary = wsi->ws->opcode ==
|
||||
LWSWSOPC_BINARY_FRAME;
|
||||
break;
|
||||
}
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_err("unknown spec version %02d\n",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN:
|
||||
|
||||
wsi->ws->this_frame_masked = !!(c & 0x80);
|
||||
|
||||
switch (c & 0x7f) {
|
||||
case 126:
|
||||
/* control frames are not allowed to have big lengths */
|
||||
if (wsi->ws->opcode & 8)
|
||||
goto illegal_ctl_length;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
|
||||
break;
|
||||
case 127:
|
||||
/* control frames are not allowed to have big lengths */
|
||||
if (wsi->ws->opcode & 8)
|
||||
goto illegal_ctl_length;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
|
||||
break;
|
||||
default:
|
||||
wsi->ws->rx_packet_length = c & 0x7f;
|
||||
if (wsi->ws->this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->ws->rx_packet_length) {
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_WS_FRAME_PAYLOAD;
|
||||
} else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
|
||||
wsi->ws->rx_packet_length = c << 8;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
|
||||
wsi->ws->rx_packet_length |= c;
|
||||
if (wsi->ws->this_frame_masked)
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->ws->rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_WS_FRAME_PAYLOAD;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
|
||||
if (c & 0x80) {
|
||||
lwsl_warn("b63 of length must be zero\n");
|
||||
/* kill the connection */
|
||||
return -1;
|
||||
}
|
||||
#if defined __LP64__
|
||||
wsi->ws->rx_packet_length = ((size_t)c) << 56;
|
||||
#else
|
||||
wsi->ws->rx_packet_length = 0;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
|
||||
#if defined __LP64__
|
||||
wsi->ws->rx_packet_length |= ((size_t)c) << 48;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
|
||||
#if defined __LP64__
|
||||
wsi->ws->rx_packet_length |= ((size_t)c) << 40;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
|
||||
#if defined __LP64__
|
||||
wsi->ws->rx_packet_length |= ((size_t)c) << 32;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
|
||||
wsi->ws->rx_packet_length |= ((size_t)c) << 24;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
|
||||
wsi->ws->rx_packet_length |= ((size_t)c) << 16;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
|
||||
wsi->ws->rx_packet_length |= ((size_t)c) << 8;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
|
||||
wsi->ws->rx_packet_length |= (size_t)c;
|
||||
if (wsi->ws->this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->ws->rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_WS_FRAME_PAYLOAD;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
|
||||
wsi->ws->mask[0] = c;
|
||||
if (c)
|
||||
wsi->ws->all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
|
||||
wsi->ws->mask[1] = c;
|
||||
if (c)
|
||||
wsi->ws->all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
|
||||
wsi->ws->mask[2] = c;
|
||||
if (c)
|
||||
wsi->ws->all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
|
||||
wsi->ws->mask[3] = c;
|
||||
if (c)
|
||||
wsi->ws->all_zero_nonce = 0;
|
||||
|
||||
if (wsi->ws->rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_WS_FRAME_PAYLOAD;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_WS_FRAME_PAYLOAD:
|
||||
|
||||
assert(wsi->ws->rx_ubuf);
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (wsi->ws->rx_draining_ext)
|
||||
goto drain_extension;
|
||||
#endif
|
||||
if (wsi->ws->this_frame_masked && !wsi->ws->all_zero_nonce)
|
||||
c ^= wsi->ws->mask[(wsi->ws->mask_idx++) & 3];
|
||||
|
||||
wsi->ws->rx_ubuf[LWS_PRE + (wsi->ws->rx_ubuf_head++)] = c;
|
||||
|
||||
if (--wsi->ws->rx_packet_length == 0) {
|
||||
/* spill because we have the whole frame */
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there's no protocol max frame size given, we are
|
||||
* supposed to default to context->pt_serv_buf_size
|
||||
*/
|
||||
if (!wsi->protocol->rx_buffer_size &&
|
||||
wsi->ws->rx_ubuf_head != wsi->context->pt_serv_buf_size)
|
||||
break;
|
||||
|
||||
if (wsi->protocol->rx_buffer_size &&
|
||||
wsi->ws->rx_ubuf_head != wsi->protocol->rx_buffer_size)
|
||||
break;
|
||||
|
||||
/* spill because we filled our rx buffer */
|
||||
spill:
|
||||
|
||||
handled = 0;
|
||||
|
||||
/*
|
||||
* is this frame a control packet we should take care of at this
|
||||
* layer? If so service it and hide it from the user callback
|
||||
*/
|
||||
|
||||
switch (wsi->ws->opcode) {
|
||||
case LWSWSOPC_CLOSE:
|
||||
pp = (unsigned char *)&wsi->ws->rx_ubuf[LWS_PRE];
|
||||
if (lws_check_opt(wsi->context->options,
|
||||
LWS_SERVER_OPTION_VALIDATE_UTF8) &&
|
||||
wsi->ws->rx_ubuf_head > 2 &&
|
||||
lws_check_utf8(&wsi->ws->utf8, pp + 2,
|
||||
wsi->ws->rx_ubuf_head - 2))
|
||||
goto utf8_fail;
|
||||
|
||||
/* is this an acknowledgment of our close? */
|
||||
if (lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) {
|
||||
/*
|
||||
* fine he has told us he is closing too, let's
|
||||
* finish our close
|
||||
*/
|
||||
lwsl_parser("seen server's close ack\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lwsl_parser("client sees server close len = %d\n",
|
||||
wsi->ws->rx_ubuf_head);
|
||||
if (wsi->ws->rx_ubuf_head >= 2) {
|
||||
close_code = (pp[0] << 8) | pp[1];
|
||||
if (close_code < 1000 ||
|
||||
close_code == 1004 ||
|
||||
close_code == 1005 ||
|
||||
close_code == 1006 ||
|
||||
close_code == 1012 ||
|
||||
close_code == 1013 ||
|
||||
close_code == 1014 ||
|
||||
close_code == 1015 ||
|
||||
(close_code >= 1016 && close_code < 3000)
|
||||
) {
|
||||
pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
|
||||
pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff;
|
||||
}
|
||||
}
|
||||
if (user_callback_handle_rxflow(
|
||||
wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
|
||||
wsi->user_space, pp,
|
||||
wsi->ws->rx_ubuf_head))
|
||||
return -1;
|
||||
|
||||
memcpy(wsi->ws->ping_payload_buf + LWS_PRE, pp,
|
||||
wsi->ws->rx_ubuf_head);
|
||||
wsi->ws->close_in_ping_buffer_len = wsi->ws->rx_ubuf_head;
|
||||
|
||||
lwsl_info("%s: scheduling return close as ack\n", __func__);
|
||||
__lws_change_pollfd(wsi, LWS_POLLIN, 0);
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 3);
|
||||
wsi->waiting_to_send_close_frame = 1;
|
||||
wsi->close_needs_ack = 0;
|
||||
lwsi_set_state(wsi, LRS_WAITING_TO_SEND_CLOSE);
|
||||
lws_callback_on_writable(wsi);
|
||||
handled = 1;
|
||||
break;
|
||||
|
||||
case LWSWSOPC_PING:
|
||||
lwsl_info("received %d byte ping, sending pong\n",
|
||||
wsi->ws->rx_ubuf_head);
|
||||
|
||||
/* he set a close reason on this guy, ignore PING */
|
||||
if (wsi->ws->close_in_ping_buffer_len)
|
||||
goto ping_drop;
|
||||
|
||||
if (wsi->ws->ping_pending_flag) {
|
||||
/*
|
||||
* there is already a pending ping payload
|
||||
* we should just log and drop
|
||||
*/
|
||||
lwsl_parser("DROP PING since one pending\n");
|
||||
goto ping_drop;
|
||||
}
|
||||
|
||||
/* control packets can only be < 128 bytes long */
|
||||
if (wsi->ws->rx_ubuf_head > 128 - 3) {
|
||||
lwsl_parser("DROP PING payload too large\n");
|
||||
goto ping_drop;
|
||||
}
|
||||
|
||||
/* stash the pong payload */
|
||||
memcpy(wsi->ws->ping_payload_buf + LWS_PRE,
|
||||
&wsi->ws->rx_ubuf[LWS_PRE],
|
||||
wsi->ws->rx_ubuf_head);
|
||||
|
||||
wsi->ws->ping_payload_len = wsi->ws->rx_ubuf_head;
|
||||
wsi->ws->ping_pending_flag = 1;
|
||||
|
||||
/* get it sent as soon as possible */
|
||||
lws_callback_on_writable(wsi);
|
||||
ping_drop:
|
||||
wsi->ws->rx_ubuf_head = 0;
|
||||
handled = 1;
|
||||
break;
|
||||
|
||||
case LWSWSOPC_PONG:
|
||||
lwsl_info("client received pong\n");
|
||||
lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
|
||||
wsi->ws->rx_ubuf_head);
|
||||
|
||||
if (wsi->pending_timeout ==
|
||||
PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG) {
|
||||
lwsl_info("%p: received expected PONG\n", wsi);
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
/* issue it */
|
||||
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
|
||||
break;
|
||||
|
||||
case LWSWSOPC_CONTINUATION:
|
||||
case LWSWSOPC_TEXT_FRAME:
|
||||
case LWSWSOPC_BINARY_FRAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* not handled or failed */
|
||||
lwsl_ext("Unhandled ext opc 0x%x\n", wsi->ws->opcode);
|
||||
wsi->ws->rx_ubuf_head = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* No it's real payload, pass it up to the user callback.
|
||||
* It's nicely buffered with the pre-padding taken care of
|
||||
* so it can be sent straight out again using lws_write
|
||||
*/
|
||||
if (handled)
|
||||
goto already_done;
|
||||
|
||||
ebuf.token = &wsi->ws->rx_ubuf[LWS_PRE];
|
||||
ebuf.len = wsi->ws->rx_ubuf_head;
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
drain_extension:
|
||||
lwsl_ext("%s: passing %d to ext\n", __func__, ebuf.len);
|
||||
|
||||
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &ebuf, 0);
|
||||
lwsl_ext("Ext RX returned %d\n", n);
|
||||
if (n < 0) {
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
lwsl_debug("post inflate ebuf len %d\n", ebuf.len);
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (rx_draining_ext && !ebuf.len) {
|
||||
lwsl_debug(" --- ending drain on 0 read result\n");
|
||||
goto already_done;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
|
||||
if (lws_check_utf8(&wsi->ws->utf8,
|
||||
(unsigned char *)ebuf.token,
|
||||
ebuf.len)) {
|
||||
lws_close_reason(wsi,
|
||||
LWS_CLOSE_STATUS_INVALID_PAYLOAD,
|
||||
(uint8_t *)"bad utf8", 8);
|
||||
goto utf8_fail;
|
||||
}
|
||||
|
||||
/* we are ending partway through utf-8 character? */
|
||||
if (!wsi->ws->rx_packet_length && wsi->ws->final &&
|
||||
wsi->ws->utf8
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
&& !n
|
||||
#endif
|
||||
) {
|
||||
lwsl_info("FINAL utf8 error\n");
|
||||
lws_close_reason(wsi,
|
||||
LWS_CLOSE_STATUS_INVALID_PAYLOAD,
|
||||
(uint8_t *)"partial utf8", 12);
|
||||
utf8_fail:
|
||||
lwsl_info("utf8 error\n");
|
||||
lwsl_hexdump_info(ebuf.token, ebuf.len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ebuf.len < 0 &&
|
||||
callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
|
||||
goto already_done;
|
||||
|
||||
if (!ebuf.token)
|
||||
goto already_done;
|
||||
|
||||
ebuf.token[ebuf.len] = '\0';
|
||||
|
||||
if (!wsi->protocol->callback)
|
||||
goto already_done;
|
||||
|
||||
if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
|
||||
lwsl_info("Client doing pong callback\n");
|
||||
|
||||
if (
|
||||
/* coverity says dead code otherwise */
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
n &&
|
||||
#endif
|
||||
ebuf.len)
|
||||
/* extension had more... main loop will come back
|
||||
* we want callback to be done with this set, if so,
|
||||
* because lws_is_final() hides it was final until the
|
||||
* last chunk
|
||||
*/
|
||||
lws_add_wsi_to_draining_ext_list(wsi);
|
||||
else
|
||||
lws_remove_wsi_from_draining_ext_list(wsi);
|
||||
|
||||
if (lwsi_state(wsi) == LRS_RETURNED_CLOSE ||
|
||||
lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE ||
|
||||
lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK)
|
||||
goto already_done;
|
||||
|
||||
m = wsi->protocol->callback(wsi,
|
||||
(enum lws_callback_reasons)callback_action,
|
||||
wsi->user_space, ebuf.token, ebuf.len);
|
||||
|
||||
wsi->ws->first_fragment = 0;
|
||||
|
||||
// lwsl_notice("%s: bulk ws rx: input used %d, output %d\n",
|
||||
// __func__, wsi->ws->rx_ubuf_head, ebuf.len);
|
||||
|
||||
/* if user code wants to close, let caller know */
|
||||
if (m)
|
||||
return 1;
|
||||
|
||||
already_done:
|
||||
wsi->ws->rx_ubuf_head = 0;
|
||||
break;
|
||||
default:
|
||||
lwsl_err("client rx illegal state\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
illegal_ctl_length:
|
||||
lwsl_warn("Control frame asking for extended length is illegal\n");
|
||||
|
||||
/* kill the connection */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -1,629 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 <core/private.h>
|
||||
|
||||
/*
|
||||
* In-place str to lower case
|
||||
*/
|
||||
|
||||
static void
|
||||
strtolower(char *s)
|
||||
{
|
||||
while (*s) {
|
||||
#ifdef LWS_PLAT_OPTEE
|
||||
int tolower_optee(int c);
|
||||
*s = tolower_optee((int)*s);
|
||||
#else
|
||||
*s = tolower((int)*s);
|
||||
#endif
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lws_create_client_ws_object(struct lws_client_connect_info *i, struct lws *wsi)
|
||||
{
|
||||
int v = SPEC_LATEST_SUPPORTED;
|
||||
|
||||
/* allocate the ws struct for the wsi */
|
||||
wsi->ws = lws_zalloc(sizeof(*wsi->ws), "client ws struct");
|
||||
if (!wsi->ws) {
|
||||
lwsl_notice("OOM\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -1 means just use latest supported */
|
||||
if (i->ietf_version_or_minus_one != -1 &&
|
||||
i->ietf_version_or_minus_one)
|
||||
v = i->ietf_version_or_minus_one;
|
||||
|
||||
wsi->ws->ietf_spec_revision = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
int
|
||||
lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
|
||||
{
|
||||
if ((lwsi_state(wsi) != LRS_WAITING_PROXY_REPLY) &&
|
||||
(lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE) &&
|
||||
(lwsi_state(wsi) != LRS_WAITING_SERVER_REPLY) &&
|
||||
!lwsi_role_client(wsi))
|
||||
return 0;
|
||||
|
||||
// lwsl_notice("%s: hs client gets %d in\n", __func__, (int)len);
|
||||
|
||||
while (len) {
|
||||
/*
|
||||
* we were accepting input but now we stopped doing so
|
||||
*/
|
||||
if (lws_is_flowcontrolled(wsi)) {
|
||||
//lwsl_notice("%s: caching %ld\n", __func__, (long)len);
|
||||
lws_rxflow_cache(wsi, *buf, 0, (int)len);
|
||||
*buf += len;
|
||||
return 0;
|
||||
}
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (wsi->ws->rx_draining_ext) {
|
||||
int m;
|
||||
|
||||
//lwsl_notice("%s: draining ext\n", __func__);
|
||||
if (lwsi_role_client(wsi))
|
||||
m = lws_ws_client_rx_sm(wsi, 0);
|
||||
else
|
||||
m = lws_ws_rx_sm(wsi, 0, 0);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* caller will account for buflist usage */
|
||||
|
||||
if (lws_ws_client_rx_sm(wsi, *(*buf)++)) {
|
||||
lwsl_notice("%s: client_rx_sm exited, DROPPING %d\n",
|
||||
__func__, (int)len);
|
||||
return -1;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
// lwsl_notice("%s: finished with %ld\n", __func__, (long)len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
lws_generate_client_ws_handshake(struct lws *wsi, char *p)
|
||||
{
|
||||
char buf[128], hash[20], key_b64[40];
|
||||
int n;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
const struct lws_extension *ext;
|
||||
int ext_count = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* create the random key
|
||||
*/
|
||||
n = lws_get_random(wsi->context, hash, 16);
|
||||
if (n != 16) {
|
||||
lwsl_err("Unable to read from random dev %s\n",
|
||||
SYSTEM_RANDOM_FILEPATH);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
|
||||
|
||||
p += sprintf(p, "Upgrade: websocket\x0d\x0a"
|
||||
"Connection: Upgrade\x0d\x0a"
|
||||
"Sec-WebSocket-Key: ");
|
||||
strcpy(p, key_b64);
|
||||
p += strlen(key_b64);
|
||||
p += sprintf(p, "\x0d\x0a");
|
||||
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
|
||||
p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi,
|
||||
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS));
|
||||
|
||||
/* tell the server what extensions we could support */
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
ext = wsi->vhost->ws.extensions;
|
||||
while (ext && ext->callback) {
|
||||
|
||||
n = wsi->vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
|
||||
wsi->user_space, (char *)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
|
||||
p += sprintf(p, "Sec-WebSocket-Extensions: ");
|
||||
p += sprintf(p, "%s", ext->client_offer);
|
||||
ext_count++;
|
||||
|
||||
ext++;
|
||||
}
|
||||
if (ext_count)
|
||||
p += sprintf(p, "\x0d\x0a");
|
||||
#endif
|
||||
|
||||
if (wsi->ws->ietf_spec_revision)
|
||||
p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
|
||||
/* prepare the expected server accept response */
|
||||
|
||||
key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
|
||||
n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
|
||||
key_b64);
|
||||
|
||||
lws_SHA1((unsigned char *)buf, n, (unsigned char *)hash);
|
||||
|
||||
lws_b64_encode_string(hash, 20,
|
||||
wsi->http.ah->initial_handshake_hash_base64,
|
||||
sizeof(wsi->http.ah->initial_handshake_hash_base64));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
lws_client_ws_upgrade(struct lws *wsi, const char **cce)
|
||||
{
|
||||
int n, len, okay = 0;
|
||||
struct lws_context *context = wsi->context;
|
||||
const char *pc;
|
||||
char *p;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
char *sb = (char *)&pt->serv_buf[0];
|
||||
const struct lws_ext_options *opts;
|
||||
const struct lws_extension *ext;
|
||||
char ext_name[128];
|
||||
const char *c, *a;
|
||||
char ignore;
|
||||
int more = 1;
|
||||
#endif
|
||||
|
||||
if (wsi->client_h2_substream) {/* !!! client ws-over-h2 not there yet */
|
||||
lwsl_warn("%s: client ws-over-h2 upgrade not supported yet\n",
|
||||
__func__);
|
||||
*cce = "HS: h2 / ws upgrade unsupported";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
if (wsi->http.ah->http_response == 401) {
|
||||
lwsl_warn(
|
||||
"lws_client_handshake: got bad HTTP response '%d'\n",
|
||||
wsi->http.ah->http_response);
|
||||
*cce = "HS: ws upgrade unauthorized";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
if (wsi->http.ah->http_response != 101) {
|
||||
lwsl_warn(
|
||||
"lws_client_handshake: got bad HTTP response '%d'\n",
|
||||
wsi->http.ah->http_response);
|
||||
*cce = "HS: ws upgrade response not 101";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
|
||||
lwsl_info("no ACCEPT\n");
|
||||
*cce = "HS: ACCEPT missing";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
|
||||
if (!p) {
|
||||
lwsl_info("no UPGRADE\n");
|
||||
*cce = "HS: UPGRADE missing";
|
||||
goto bail3;
|
||||
}
|
||||
strtolower(p);
|
||||
if (strcmp(p, "websocket")) {
|
||||
lwsl_warn(
|
||||
"lws_client_handshake: got bad Upgrade header '%s'\n", p);
|
||||
*cce = "HS: Upgrade to something other than websocket";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);
|
||||
if (!p) {
|
||||
lwsl_info("no Connection hdr\n");
|
||||
*cce = "HS: CONNECTION missing";
|
||||
goto bail3;
|
||||
}
|
||||
strtolower(p);
|
||||
if (strcmp(p, "upgrade")) {
|
||||
lwsl_warn("lws_client_int_s_hs: bad header %s\n", p);
|
||||
*cce = "HS: UPGRADE malformed";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
|
||||
if (!pc) {
|
||||
lwsl_parser("lws_client_int_s_hs: no protocol list\n");
|
||||
} else
|
||||
lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);
|
||||
|
||||
/*
|
||||
* confirm the protocol the server wants to talk was in the list
|
||||
* of protocols we offered
|
||||
*/
|
||||
|
||||
len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
|
||||
if (!len) {
|
||||
lwsl_info("%s: WSI_TOKEN_PROTOCOL is null\n", __func__);
|
||||
/*
|
||||
* no protocol name to work from,
|
||||
* default to first protocol
|
||||
*/
|
||||
n = 0;
|
||||
wsi->protocol = &wsi->vhost->protocols[0];
|
||||
goto check_extensions;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
|
||||
len = (int)strlen(p);
|
||||
|
||||
while (pc && *pc && !okay) {
|
||||
if (!strncmp(pc, p, len) &&
|
||||
(pc[len] == ',' || pc[len] == '\0')) {
|
||||
okay = 1;
|
||||
continue;
|
||||
}
|
||||
while (*pc && *pc++ != ',')
|
||||
;
|
||||
while (*pc && *pc == ' ')
|
||||
pc++;
|
||||
}
|
||||
|
||||
if (!okay) {
|
||||
lwsl_info("%s: got bad protocol %s\n", __func__, p);
|
||||
*cce = "HS: PROTOCOL malformed";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/*
|
||||
* identify the selected protocol struct and set it
|
||||
*/
|
||||
n = 0;
|
||||
/* keep client connection pre-bound protocol */
|
||||
if (!lwsi_role_client(wsi))
|
||||
wsi->protocol = NULL;
|
||||
|
||||
while (wsi->vhost->protocols[n].callback) {
|
||||
if (!wsi->protocol &&
|
||||
strcmp(p, wsi->vhost->protocols[n].name) == 0) {
|
||||
wsi->protocol = &wsi->vhost->protocols[n];
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
if (!wsi->vhost->protocols[n].callback) { /* no match */
|
||||
/* if server, that's already fatal */
|
||||
if (!lwsi_role_client(wsi)) {
|
||||
lwsl_info("%s: fail protocol %s\n", __func__, p);
|
||||
*cce = "HS: Cannot match protocol";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/* for client, find the index of our pre-bound protocol */
|
||||
|
||||
n = 0;
|
||||
while (wsi->vhost->protocols[n].callback) {
|
||||
if (wsi->protocol && strcmp(wsi->protocol->name,
|
||||
wsi->vhost->protocols[n].name) == 0) {
|
||||
wsi->protocol = &wsi->vhost->protocols[n];
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
if (!wsi->vhost->protocols[n].callback) {
|
||||
if (wsi->protocol)
|
||||
lwsl_err("Failed to match protocol %s\n",
|
||||
wsi->protocol->name);
|
||||
else
|
||||
lwsl_err("No protocol on client\n");
|
||||
goto bail2;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_debug("Selected protocol %s\n", wsi->protocol->name);
|
||||
|
||||
check_extensions:
|
||||
/*
|
||||
* stitch protocol choice into the vh protocol linked list
|
||||
* We always insert ourselves at the start of the list
|
||||
*
|
||||
* X <-> B
|
||||
* X <-> pAn <-> pB
|
||||
*/
|
||||
|
||||
lws_vhost_lock(wsi->vhost);
|
||||
|
||||
wsi->same_vh_protocol_prev = /* guy who points to us */
|
||||
&wsi->vhost->same_vh_protocol_list[n];
|
||||
wsi->same_vh_protocol_next = /* old first guy is our next */
|
||||
wsi->vhost->same_vh_protocol_list[n];
|
||||
/* we become the new first guy */
|
||||
wsi->vhost->same_vh_protocol_list[n] = wsi;
|
||||
|
||||
if (wsi->same_vh_protocol_next)
|
||||
/* old first guy points back to us now */
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
&wsi->same_vh_protocol_next;
|
||||
wsi->on_same_vh_list = 1;
|
||||
|
||||
lws_vhost_unlock(wsi->vhost);
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
/* instantiate the accepted extensions */
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
|
||||
lwsl_ext("no client extensions allowed by server\n");
|
||||
goto check_accept;
|
||||
}
|
||||
|
||||
/*
|
||||
* break down the list of server accepted extensions
|
||||
* and go through matching them or identifying bogons
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, sb, context->pt_serv_buf_size,
|
||||
WSI_TOKEN_EXTENSIONS) < 0) {
|
||||
lwsl_warn("ext list from server failed to copy\n");
|
||||
*cce = "HS: EXT: list too big";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
c = sb;
|
||||
n = 0;
|
||||
ignore = 0;
|
||||
a = NULL;
|
||||
while (more) {
|
||||
|
||||
if (*c && (*c != ',' && *c != '\t')) {
|
||||
if (*c == ';') {
|
||||
ignore = 1;
|
||||
if (!a)
|
||||
a = c + 1;
|
||||
}
|
||||
if (ignore || *c == ' ') {
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ext_name[n] = *c++;
|
||||
if (n < (int)sizeof(ext_name) - 1)
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = '\0';
|
||||
ignore = 0;
|
||||
if (!*c)
|
||||
more = 0;
|
||||
else {
|
||||
c++;
|
||||
if (!n)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check we actually support it */
|
||||
|
||||
lwsl_notice("checking client ext %s\n", ext_name);
|
||||
|
||||
n = 0;
|
||||
ext = wsi->vhost->ws.extensions;
|
||||
while (ext && ext->callback) {
|
||||
if (strcmp(ext_name, ext->name)) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
n = 1;
|
||||
lwsl_notice("instantiating client ext %s\n", ext_name);
|
||||
|
||||
/* instantiate the extension on this conn */
|
||||
|
||||
wsi->ws->active_extensions[wsi->ws->count_act_ext] = ext;
|
||||
|
||||
/* allow him to construct his ext instance */
|
||||
|
||||
if (ext->callback(lws_get_context(wsi), ext, wsi,
|
||||
LWS_EXT_CB_CLIENT_CONSTRUCT,
|
||||
(void *)&wsi->ws->act_ext_user[wsi->ws->count_act_ext],
|
||||
(void *)&opts, 0)) {
|
||||
lwsl_info(" ext %s failed construction\n",
|
||||
ext_name);
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* allow the user code to override ext defaults if it
|
||||
* wants to
|
||||
*/
|
||||
ext_name[0] = '\0';
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_WS_EXT_DEFAULTS,
|
||||
(char *)ext->name, ext_name,
|
||||
sizeof(ext_name))) {
|
||||
*cce = "HS: EXT: failed setting defaults";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
if (ext_name[0] &&
|
||||
lws_ext_parse_options(ext, wsi, wsi->ws->act_ext_user[
|
||||
wsi->ws->count_act_ext], opts, ext_name,
|
||||
(int)strlen(ext_name))) {
|
||||
lwsl_err("%s: unable to parse user defaults '%s'",
|
||||
__func__, ext_name);
|
||||
*cce = "HS: EXT: failed parsing defaults";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/*
|
||||
* give the extension the server options
|
||||
*/
|
||||
if (a && lws_ext_parse_options(ext, wsi,
|
||||
wsi->ws->act_ext_user[wsi->ws->count_act_ext],
|
||||
opts, a, lws_ptr_diff(c, a))) {
|
||||
lwsl_err("%s: unable to parse remote def '%s'",
|
||||
__func__, a);
|
||||
*cce = "HS: EXT: failed parsing options";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
if (ext->callback(lws_get_context(wsi), ext, wsi,
|
||||
LWS_EXT_CB_OPTION_CONFIRM,
|
||||
wsi->ws->act_ext_user[wsi->ws->count_act_ext],
|
||||
NULL, 0)) {
|
||||
lwsl_err("%s: ext %s rejects server options %s",
|
||||
__func__, ext->name, a);
|
||||
*cce = "HS: EXT: Rejects server options";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
wsi->ws->count_act_ext++;
|
||||
|
||||
ext++;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
lwsl_warn("Unknown ext '%s'!\n", ext_name);
|
||||
*cce = "HS: EXT: unknown ext";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
a = NULL;
|
||||
n = 0;
|
||||
}
|
||||
|
||||
check_accept:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Confirm his accept token is the one we precomputed
|
||||
*/
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
|
||||
if (strcmp(p, wsi->http.ah->initial_handshake_hash_base64)) {
|
||||
lwsl_warn("lws_client_int_s_hs: accept '%s' wrong vs '%s'\n", p,
|
||||
wsi->http.ah->initial_handshake_hash_base64);
|
||||
*cce = "HS: Accept hash wrong";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
if (lws_ensure_user_space(wsi)) {
|
||||
lwsl_err("Problem allocating wsi user mem\n");
|
||||
*cce = "HS: OOM";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/*
|
||||
* we seem to be good to go, give client last chance to check
|
||||
* headers and OK it
|
||||
*/
|
||||
if (wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
|
||||
wsi->user_space, NULL, 0)) {
|
||||
*cce = "HS: Rejected by filter cb";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/* clear his proxy connection timeout */
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
/* free up his parsing allocations */
|
||||
lws_header_table_detach(wsi, 0);
|
||||
|
||||
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
|
||||
&role_ops_ws);
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, then
|
||||
* use a big default for compatibility
|
||||
*/
|
||||
n = (int)wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = context->pt_serv_buf_size;
|
||||
n += LWS_PRE;
|
||||
wsi->ws->rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */,
|
||||
"client frame buffer");
|
||||
if (!wsi->ws->rx_ubuf) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
*cce = "HS: OOM";
|
||||
goto bail2;
|
||||
}
|
||||
wsi->ws->rx_ubuf_alloc = n;
|
||||
lwsl_info("Allocating client RX buffer %d\n", n);
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
|
||||
(const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
*cce = "HS: SO_SNDBUF failed";
|
||||
goto bail3;
|
||||
}
|
||||
#endif
|
||||
|
||||
lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
|
||||
|
||||
/* call him back to inform him he is up */
|
||||
|
||||
if (wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED,
|
||||
wsi->user_space, NULL, 0)) {
|
||||
*cce = "HS: Rejected at CLIENT_ESTABLISHED";
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail3:
|
||||
return 3;
|
||||
|
||||
bail2:
|
||||
return 2;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h if LWS_ROLE_WS
|
||||
*/
|
||||
|
||||
extern struct lws_role_ops role_ops_ws;
|
||||
|
||||
#define lwsi_role_ws(wsi) (wsi->role_ops == &role_ops_ws)
|
||||
|
||||
enum lws_rx_parse_state {
|
||||
LWS_RXPS_NEW,
|
||||
|
||||
LWS_RXPS_04_mask_1,
|
||||
LWS_RXPS_04_mask_2,
|
||||
LWS_RXPS_04_mask_3,
|
||||
|
||||
LWS_RXPS_04_FRAME_HDR_1,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN16_2,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN16_1,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_8,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_7,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_6,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_5,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_4,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_3,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_2,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_1,
|
||||
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1,
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_2,
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_3,
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_4,
|
||||
|
||||
LWS_RXPS_WS_FRAME_PAYLOAD
|
||||
};
|
||||
|
||||
enum lws_websocket_opcodes_07 {
|
||||
LWSWSOPC_CONTINUATION = 0,
|
||||
LWSWSOPC_TEXT_FRAME = 1,
|
||||
LWSWSOPC_BINARY_FRAME = 2,
|
||||
|
||||
LWSWSOPC_NOSPEC__MUX = 7,
|
||||
|
||||
/* control extensions 8+ */
|
||||
|
||||
LWSWSOPC_CLOSE = 8,
|
||||
LWSWSOPC_PING = 9,
|
||||
LWSWSOPC_PONG = 0xa,
|
||||
};
|
||||
|
||||
/* this is not usable directly by user code any more, lws_close_reason() */
|
||||
#define LWS_WRITE_CLOSE 4
|
||||
|
||||
#define ALREADY_PROCESSED_IGNORE_CHAR 1
|
||||
#define ALREADY_PROCESSED_NO_CB 2
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
struct lws_vhost_role_ws {
|
||||
const struct lws_extension *extensions;
|
||||
};
|
||||
|
||||
struct lws_pt_role_ws {
|
||||
struct lws *rx_draining_ext_list;
|
||||
struct lws *tx_draining_ext_list;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct _lws_websocket_related {
|
||||
char *rx_ubuf;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
const struct lws_extension *active_extensions[LWS_MAX_EXTENSIONS_ACTIVE];
|
||||
void *act_ext_user[LWS_MAX_EXTENSIONS_ACTIVE];
|
||||
struct lws *rx_draining_ext_list;
|
||||
struct lws *tx_draining_ext_list;
|
||||
#endif
|
||||
/* Also used for close content... control opcode == < 128 */
|
||||
uint8_t ping_payload_buf[128 - 3 + LWS_PRE];
|
||||
uint8_t mask[4];
|
||||
|
||||
time_t time_next_ping_check;
|
||||
size_t rx_packet_length;
|
||||
uint32_t rx_ubuf_head;
|
||||
uint32_t rx_ubuf_alloc;
|
||||
|
||||
uint8_t ping_payload_len;
|
||||
uint8_t mask_idx;
|
||||
uint8_t opcode;
|
||||
uint8_t rsv;
|
||||
uint8_t rsv_first_msg;
|
||||
/* zero if no info, or length including 2-byte close code */
|
||||
uint8_t close_in_ping_buffer_len;
|
||||
uint8_t utf8;
|
||||
uint8_t stashed_write_type;
|
||||
uint8_t tx_draining_stashed_wp;
|
||||
uint8_t ietf_spec_revision;
|
||||
|
||||
unsigned int final:1;
|
||||
unsigned int frame_is_binary:1;
|
||||
unsigned int all_zero_nonce:1;
|
||||
unsigned int this_frame_masked:1;
|
||||
unsigned int inside_frame:1; /* next write will be more of frame */
|
||||
unsigned int clean_buffer:1; /* buffer not rewritten by extension */
|
||||
unsigned int payload_is_close:1; /* process as PONG, but it is close */
|
||||
unsigned int ping_pending_flag:1;
|
||||
unsigned int continuation_possible:1;
|
||||
unsigned int owed_a_fin:1;
|
||||
unsigned int check_utf8:1;
|
||||
unsigned int defeat_check_utf8:1;
|
||||
unsigned int stashed_write_pending:1;
|
||||
unsigned int send_check_ping:1;
|
||||
unsigned int first_fragment:1;
|
||||
unsigned int peer_has_sent_close:1;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
unsigned int extension_data_pending:1;
|
||||
unsigned int rx_draining_ext:1;
|
||||
unsigned int tx_draining_ext:1;
|
||||
|
||||
uint8_t count_act_ext;
|
||||
#endif
|
||||
};
|
||||
|
||||
int
|
||||
lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len);
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
LWS_VISIBLE void
|
||||
lws_context_init_extensions(const struct lws_context_creation_info *info,
|
||||
struct lws_context *context);
|
||||
LWS_EXTERN int
|
||||
lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,
|
||||
void *v, size_t len);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_ext_cb_active(struct lws *wsi, int reason, void *buf, int len);
|
||||
LWS_EXTERN int
|
||||
lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi, int reason,
|
||||
void *arg, int len);
|
||||
#endif
|
||||
|
||||
int
|
||||
handshake_0405(struct lws_context *context, struct lws *wsi);
|
||||
int
|
||||
lws_process_ws_upgrade(struct lws *wsi);
|
||||
int
|
||||
lws_server_init_wsi_for_ws(struct lws *wsi);
|
|
@ -1,836 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 <core/private.h>
|
||||
|
||||
#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
static int
|
||||
lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
char ext_name[64], *args, *end = (*p) + budget - 1;
|
||||
const struct lws_ext_options *opts, *po;
|
||||
const struct lws_extension *ext;
|
||||
struct lws_ext_option_arg oa;
|
||||
int n, m, more = 1;
|
||||
int ext_count = 0;
|
||||
char ignore;
|
||||
char *c;
|
||||
|
||||
/*
|
||||
* 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 *)pt->serv_buf, context->pt_serv_buf_size,
|
||||
WSI_TOKEN_EXTENSIONS) < 0)
|
||||
return 1;
|
||||
|
||||
c = (char *)pt->serv_buf;
|
||||
lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c);
|
||||
wsi->ws->count_act_ext = 0;
|
||||
ignore = 0;
|
||||
n = 0;
|
||||
args = NULL;
|
||||
|
||||
/*
|
||||
* We may get a simple request
|
||||
*
|
||||
* Sec-WebSocket-Extensions: permessage-deflate
|
||||
*
|
||||
* or an elaborated one with requested options
|
||||
*
|
||||
* Sec-WebSocket-Extensions: permessage-deflate; \
|
||||
* server_no_context_takeover; \
|
||||
* client_no_context_takeover
|
||||
*/
|
||||
|
||||
while (more) {
|
||||
|
||||
if (c >= (char *)pt->serv_buf + 255)
|
||||
return -1;
|
||||
|
||||
if (*c && (*c != ',' && *c != '\t')) {
|
||||
if (*c == ';') {
|
||||
ignore = 1;
|
||||
if (!args)
|
||||
args = c + 1;
|
||||
}
|
||||
if (ignore || *c == ' ') {
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = *c++;
|
||||
if (n < (int)sizeof(ext_name) - 1)
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = '\0';
|
||||
|
||||
ignore = 0;
|
||||
if (!*c)
|
||||
more = 0;
|
||||
else {
|
||||
c++;
|
||||
if (!n)
|
||||
continue;
|
||||
}
|
||||
|
||||
while (args && *args && *args == ' ')
|
||||
args++;
|
||||
|
||||
/* check a client's extension against our support */
|
||||
|
||||
ext = wsi->vhost->ws.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
|
||||
* confirm he only gave it once
|
||||
*/
|
||||
for (m = 0; m < wsi->ws->count_act_ext; m++)
|
||||
if (wsi->ws->active_extensions[m] == ext) {
|
||||
lwsl_info("extension mentioned twice\n");
|
||||
return 1; /* shenanigans */
|
||||
}
|
||||
|
||||
/*
|
||||
* ask user code if it's OK to apply it on this
|
||||
* particular connection + protocol
|
||||
*/
|
||||
m = (wsi->protocol->callback)(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 (m) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply it */
|
||||
|
||||
ext_count++;
|
||||
|
||||
/* instantiate the extension on this conn */
|
||||
|
||||
wsi->ws->active_extensions[wsi->ws->count_act_ext] = ext;
|
||||
|
||||
/* allow him to construct his context */
|
||||
|
||||
if (ext->callback(lws_get_context(wsi), ext, wsi,
|
||||
LWS_EXT_CB_CONSTRUCT,
|
||||
(void *)&wsi->ws->act_ext_user[
|
||||
wsi->ws->count_act_ext],
|
||||
(void *)&opts, 0)) {
|
||||
lwsl_info("ext %s failed construction\n",
|
||||
ext_name);
|
||||
ext_count--;
|
||||
ext++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext_count > 1)
|
||||
*(*p)++ = ',';
|
||||
else
|
||||
LWS_CPYAPP(*p,
|
||||
"\x0d\x0aSec-WebSocket-Extensions: ");
|
||||
*p += lws_snprintf(*p, (end - *p), "%s", ext_name);
|
||||
|
||||
/*
|
||||
* The client may send a bunch of different option
|
||||
* sets for the same extension, we are supposed to
|
||||
* pick one we like the look of. The option sets are
|
||||
* separated by comma.
|
||||
*
|
||||
* Actually we just either accept the first one or
|
||||
* nothing.
|
||||
*
|
||||
* Go through the options trying to apply the
|
||||
* recognized ones
|
||||
*/
|
||||
|
||||
lwsl_info("ext args %s\n", args);
|
||||
|
||||
while (args && *args && *args != ',') {
|
||||
while (*args == ' ')
|
||||
args++;
|
||||
po = opts;
|
||||
while (po->name) {
|
||||
/* only support arg-less options... */
|
||||
if (po->type != EXTARG_NONE ||
|
||||
strncmp(args, po->name,
|
||||
strlen(po->name))) {
|
||||
po++;
|
||||
continue;
|
||||
}
|
||||
oa.option_name = NULL;
|
||||
oa.option_index = (int)(po - opts);
|
||||
oa.start = NULL;
|
||||
oa.len = 0;
|
||||
lwsl_info("setting '%s'\n", po->name);
|
||||
if (!ext->callback(lws_get_context(wsi),
|
||||
ext, wsi,
|
||||
LWS_EXT_CB_OPTION_SET,
|
||||
wsi->ws->act_ext_user[
|
||||
wsi->ws->count_act_ext],
|
||||
&oa, (end - *p))) {
|
||||
|
||||
*p += lws_snprintf(*p, (end - *p),
|
||||
"; %s", po->name);
|
||||
lwsl_debug("adding option %s\n",
|
||||
po->name);
|
||||
}
|
||||
po++;
|
||||
}
|
||||
while (*args && *args != ',' && *args != ';')
|
||||
args++;
|
||||
|
||||
if (*args == ';')
|
||||
args++;
|
||||
}
|
||||
|
||||
wsi->ws->count_act_ext++;
|
||||
lwsl_parser("cnt_act_ext <- %d\n", wsi->ws->count_act_ext);
|
||||
|
||||
if (args && *args == ',')
|
||||
more = 0;
|
||||
|
||||
ext++;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
args = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int
|
||||
lws_process_ws_upgrade(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char protocol_list[128], protocol_name[64], *p;
|
||||
int protocol_len, hit, n = 0, non_space_char_found = 0;
|
||||
|
||||
if (!wsi->protocol)
|
||||
lwsl_err("NULL protocol at lws_read\n");
|
||||
|
||||
/*
|
||||
* It's either websocket or h2->websocket
|
||||
*
|
||||
* Select the first protocol we support from the list
|
||||
* the client sent us.
|
||||
*
|
||||
* Copy it to remove header fragmentation
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,
|
||||
WSI_TOKEN_PROTOCOL) < 0) {
|
||||
lwsl_err("protocol list too long");
|
||||
return 1;
|
||||
}
|
||||
|
||||
protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
|
||||
protocol_list[protocol_len] = '\0';
|
||||
p = protocol_list;
|
||||
hit = 0;
|
||||
|
||||
while (*p && !hit) {
|
||||
n = 0;
|
||||
non_space_char_found = 0;
|
||||
while (n < (int)sizeof(protocol_name) - 1 &&
|
||||
*p && *p != ',') {
|
||||
/* ignore leading spaces */
|
||||
if (!non_space_char_found && *p == ' ') {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
non_space_char_found = 1;
|
||||
protocol_name[n++] = *p++;
|
||||
}
|
||||
protocol_name[n] = '\0';
|
||||
if (*p)
|
||||
p++;
|
||||
|
||||
lwsl_debug("checking %s\n", protocol_name);
|
||||
|
||||
n = 0;
|
||||
while (wsi->vhost->protocols[n].callback) {
|
||||
lwsl_debug("try %s\n",
|
||||
wsi->vhost->protocols[n].name);
|
||||
|
||||
if (wsi->vhost->protocols[n].name &&
|
||||
!strcmp(wsi->vhost->protocols[n].name,
|
||||
protocol_name)) {
|
||||
wsi->protocol = &wsi->vhost->protocols[n];
|
||||
hit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
/* we didn't find a protocol he wanted? */
|
||||
|
||||
if (!hit) {
|
||||
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
|
||||
lwsl_notice("No protocol from \"%s\" supported\n",
|
||||
protocol_list);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* some clients only have one protocol and
|
||||
* do not send the protocol list header...
|
||||
* allow it and match to the vhost's default
|
||||
* protocol (which itself defaults to zero)
|
||||
*/
|
||||
lwsl_info("defaulting to prot handler %d\n",
|
||||
wsi->vhost->default_protocol_index);
|
||||
n = wsi->vhost->default_protocol_index;
|
||||
wsi->protocol = &wsi->vhost->protocols[
|
||||
(int)wsi->vhost->default_protocol_index];
|
||||
}
|
||||
|
||||
/* allocate the ws struct for the wsi */
|
||||
wsi->ws = lws_zalloc(sizeof(*wsi->ws), "ws struct");
|
||||
if (!wsi->ws) {
|
||||
lwsl_notice("OOM\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
|
||||
wsi->ws->ietf_spec_revision =
|
||||
atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
|
||||
|
||||
/* allocate wsi->user storage */
|
||||
if (lws_ensure_user_space(wsi)) {
|
||||
lwsl_notice("problem with user space\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give the user code a chance to study the request and
|
||||
* have the opportunity to deny it
|
||||
*/
|
||||
if ((wsi->protocol->callback)(wsi,
|
||||
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
|
||||
wsi->user_space,
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
|
||||
lwsl_warn("User code denied connection\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the handshake according to the protocol version the
|
||||
* client announced
|
||||
*/
|
||||
|
||||
switch (wsi->ws->ietf_spec_revision) {
|
||||
default:
|
||||
lwsl_notice("Unknown client spec version %d\n",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
wsi->ws->ietf_spec_revision = 13;
|
||||
//return 1;
|
||||
/* fallthru */
|
||||
case 13:
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->h2_stream_carries_ws) {
|
||||
if (lws_h2_ws_handshake(wsi)) {
|
||||
lwsl_notice("h2 ws handshake failed\n");
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
lwsl_parser("lws_parse calling handshake_04\n");
|
||||
if (handshake_0405(wsi->context, wsi)) {
|
||||
lwsl_notice("hs0405 has failed the connection\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
lws_same_vh_protocol_insert(wsi, n);
|
||||
|
||||
/*
|
||||
* We are upgrading to ws, so http/1.1 + h2 and keepalive + pipelined
|
||||
* header considerations about keeping the ah around no longer apply.
|
||||
*
|
||||
* However it's common for the first ws protocol data to have been
|
||||
* coalesced with the browser upgrade request and to already be in the
|
||||
* ah rx buffer.
|
||||
*/
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
if (wsi->h2_stream_carries_ws)
|
||||
lws_role_transition(wsi, LWSIFR_SERVER | LWSIFR_P_ENCAP_H2,
|
||||
LRS_ESTABLISHED, &role_ops_ws);
|
||||
else
|
||||
lws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED,
|
||||
&role_ops_ws);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_server_init_wsi_for_ws(wsi);
|
||||
lwsl_parser("accepted v%02d connection\n", wsi->ws->ietf_spec_revision);
|
||||
|
||||
lwsl_info("%s: %p: dropping ah on ws upgrade\n", __func__, wsi);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
handshake_0405(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws_process_html_args args;
|
||||
unsigned char hash[20];
|
||||
int n, accept_len;
|
||||
char *response;
|
||||
char *p;
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {
|
||||
lwsl_info("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 *)pt->serv_buf,
|
||||
"%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
|
||||
|
||||
lws_SHA1(pt->serv_buf, n, hash);
|
||||
|
||||
accept_len = lws_b64_encode_string((char *)hash, 20,
|
||||
(char *)pt->serv_buf, context->pt_serv_buf_size);
|
||||
if (accept_len < 0) {
|
||||
lwsl_warn("Base64 encoded hash too long\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
if (lws_ensure_user_space(wsi))
|
||||
goto bail;
|
||||
|
||||
/* create the response packet */
|
||||
|
||||
/* make a buffer big enough for everything */
|
||||
|
||||
response = (char *)pt->serv_buf + MAX_WEBSOCKET_04_KEY_LEN + 256 + LWS_PRE;
|
||||
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 *)pt->serv_buf);
|
||||
p += accept_len;
|
||||
|
||||
/* we can only return the protocol header if:
|
||||
* - one came in, and ... */
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
|
||||
/* - it is not an empty string */
|
||||
wsi->protocol->name &&
|
||||
wsi->protocol->name[0]) {
|
||||
LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
|
||||
p += lws_snprintf(p, 128, "%s", wsi->protocol->name);
|
||||
}
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
/*
|
||||
* Figure out which extensions the client has that we want to
|
||||
* enable on this connection, and give him back the list.
|
||||
*
|
||||
* Give him a limited write bugdet
|
||||
*/
|
||||
if (lws_extension_server_handshake(wsi, &p, 192))
|
||||
goto bail;
|
||||
#endif
|
||||
LWS_CPYAPP(p, "\x0d\x0a");
|
||||
|
||||
args.p = p;
|
||||
args.max_len = lws_ptr_diff((char *)pt->serv_buf +
|
||||
context->pt_serv_buf_size, p);
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_ADD_HEADERS,
|
||||
wsi->user_space, &args, 0))
|
||||
goto bail;
|
||||
|
||||
p = args.p;
|
||||
|
||||
/* end of response packet */
|
||||
|
||||
LWS_CPYAPP(p, "\x0d\x0a");
|
||||
|
||||
/* okay send the handshake response accepting the connection */
|
||||
|
||||
lwsl_parser("issuing resp pkt %d len\n",
|
||||
lws_ptr_diff(p, response));
|
||||
#if defined(DEBUG)
|
||||
fwrite(response, 1, p - response, stderr);
|
||||
#endif
|
||||
n = lws_write(wsi, (unsigned char *)response, p - response,
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
if (n != (p - response)) {
|
||||
lwsl_info("%s: ERROR writing to socket %d\n", __func__, n);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* alright clean up and set ourselves into established state */
|
||||
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
|
||||
{
|
||||
const char * uri_ptr =
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
|
||||
int uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
|
||||
const struct lws_http_mount *hit =
|
||||
lws_find_mount(wsi, uri_ptr, uri_len);
|
||||
if (hit && hit->cgienv &&
|
||||
wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO,
|
||||
wsi->user_space, (void *)hit->cgienv, 0))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
/* caller will free up his parsing allocations */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Once we reach LWS_RXPS_WS_FRAME_PAYLOAD, we know how much
|
||||
* to expect in that state and can deal with it in bulk more efficiently.
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
|
||||
{
|
||||
uint8_t *buffer = *buf, mask[4];
|
||||
struct lws_tokens ebuf;
|
||||
unsigned int avail = (unsigned int)len;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
unsigned int old_packet_length = (int)wsi->ws->rx_packet_length;
|
||||
#endif
|
||||
int n = 0;
|
||||
|
||||
/*
|
||||
* With zlib, we can give it as much input as we like. The pmd
|
||||
* extension will draw it down in chunks (default 1024).
|
||||
*
|
||||
* If we try to restrict how much we give it, because we must go
|
||||
* back to the event loop each time, we will drop the remainder...
|
||||
*/
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (!wsi->ws->count_act_ext)
|
||||
#endif
|
||||
{
|
||||
if (wsi->protocol->rx_buffer_size)
|
||||
avail = (int)wsi->protocol->rx_buffer_size;
|
||||
else
|
||||
avail = wsi->context->pt_serv_buf_size;
|
||||
}
|
||||
|
||||
/* do not consume more than we should */
|
||||
if (avail > wsi->ws->rx_packet_length)
|
||||
avail = (unsigned int)wsi->ws->rx_packet_length;
|
||||
|
||||
/* do not consume more than what is in the buffer */
|
||||
if (avail > len)
|
||||
avail = (unsigned int)len;
|
||||
|
||||
if (avail <= 0)
|
||||
return 0;
|
||||
|
||||
ebuf.token = (char *)buffer;
|
||||
ebuf.len = avail;
|
||||
|
||||
//lwsl_hexdump_notice(ebuf.token, ebuf.len);
|
||||
|
||||
if (!wsi->ws->all_zero_nonce) {
|
||||
|
||||
for (n = 0; n < 4; n++)
|
||||
mask[n] = wsi->ws->mask[(wsi->ws->mask_idx + n) & 3];
|
||||
|
||||
/* deal with 4-byte chunks using unwrapped loop */
|
||||
n = avail >> 2;
|
||||
while (n--) {
|
||||
*(buffer) = *(buffer) ^ mask[0];
|
||||
buffer++;
|
||||
*(buffer) = *(buffer) ^ mask[1];
|
||||
buffer++;
|
||||
*(buffer) = *(buffer) ^ mask[2];
|
||||
buffer++;
|
||||
*(buffer) = *(buffer) ^ mask[3];
|
||||
buffer++;
|
||||
}
|
||||
/* and the remaining bytes bytewise */
|
||||
for (n = 0; n < (int)(avail & 3); n++) {
|
||||
*(buffer) = *(buffer) ^ mask[n];
|
||||
buffer++;
|
||||
}
|
||||
|
||||
wsi->ws->mask_idx = (wsi->ws->mask_idx + avail) & 3;
|
||||
}
|
||||
|
||||
lwsl_info("%s: using %d of raw input (total %d on offer)\n", __func__,
|
||||
avail, (int)len);
|
||||
|
||||
(*buf) += avail;
|
||||
len -= avail;
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &ebuf, 0);
|
||||
lwsl_info("%s: ext says %d / ebuf.len %d\n", __func__, n, ebuf.len);
|
||||
#endif
|
||||
/*
|
||||
* ebuf may be pointing somewhere completely different now,
|
||||
* it's the output
|
||||
*/
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (n < 0) {
|
||||
/*
|
||||
* we may rely on this to get RX, just drop connection
|
||||
*/
|
||||
lwsl_notice("%s: LWS_EXT_CB_PAYLOAD_RX blew out\n", __func__);
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
wsi->ws->rx_packet_length -= avail;
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
/*
|
||||
* if we had an rx fragment right at the last compressed byte of the
|
||||
* message, we can get a zero length inflated output, where no prior
|
||||
* rx inflated output marked themselves with FIN, since there was
|
||||
* raw ws payload still to drain at that time.
|
||||
*
|
||||
* Then we need to generate a zero length ws rx that can be understood
|
||||
* as the message completion.
|
||||
*/
|
||||
|
||||
if (!ebuf.len && /* zero-length inflation output */
|
||||
!n && /* nothing left to drain from the inflator */
|
||||
wsi->ws->count_act_ext && /* we are using pmd */
|
||||
old_packet_length && /* we gave the inflator new input */
|
||||
!wsi->ws->rx_packet_length && /* raw ws packet payload all gone */
|
||||
wsi->ws->final && /* the raw ws packet is a FIN guy */
|
||||
wsi->protocol->callback &&
|
||||
!wsi->wsistate_pre_close) {
|
||||
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_RECEIVE,
|
||||
wsi->user_space, NULL, 0))
|
||||
return -1;
|
||||
|
||||
return avail;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ebuf.len)
|
||||
return avail;
|
||||
|
||||
if (
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
n &&
|
||||
#endif
|
||||
ebuf.len)
|
||||
/* extension had more... main loop will come back */
|
||||
lws_add_wsi_to_draining_ext_list(wsi);
|
||||
else
|
||||
lws_remove_wsi_from_draining_ext_list(wsi);
|
||||
|
||||
if (wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
|
||||
if (lws_check_utf8(&wsi->ws->utf8,
|
||||
(unsigned char *)ebuf.token, ebuf.len)) {
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,
|
||||
(uint8_t *)"bad utf8", 8);
|
||||
goto utf8_fail;
|
||||
}
|
||||
|
||||
/* we are ending partway through utf-8 character? */
|
||||
if (!wsi->ws->rx_packet_length && wsi->ws->final &&
|
||||
wsi->ws->utf8 && !n) {
|
||||
lwsl_info("FINAL utf8 error\n");
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,
|
||||
(uint8_t *)"partial utf8", 12);
|
||||
|
||||
utf8_fail:
|
||||
lwsl_info("utf8 error\n");
|
||||
lwsl_hexdump_info(ebuf.token, ebuf.len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsi->protocol->callback && !wsi->wsistate_pre_close)
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_RECEIVE,
|
||||
wsi->user_space,
|
||||
ebuf.token, ebuf.len))
|
||||
return -1;
|
||||
|
||||
wsi->ws->first_fragment = 0;
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
lwsl_info("%s: input used %d, output %d, rem len %d, rx_draining_ext %d\n",
|
||||
__func__, avail, ebuf.len, (int)len, wsi->ws->rx_draining_ext);
|
||||
#endif
|
||||
|
||||
return avail; /* how much we used from the input */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len)
|
||||
{
|
||||
int m, bulk = 0;
|
||||
|
||||
lwsl_debug("%s: received %d byte packet\n", __func__, (int)len);
|
||||
|
||||
//lwsl_hexdump_notice(*buf, len);
|
||||
|
||||
/* let the rx protocol state machine have as much as it needs */
|
||||
|
||||
while (len) {
|
||||
/*
|
||||
* we were accepting input but now we stopped doing so
|
||||
*/
|
||||
if (wsi->rxflow_bitmap) {
|
||||
lwsl_info("%s: doing rxflow\n", __func__);
|
||||
lws_rxflow_cache(wsi, *buf, 0, (int)len);
|
||||
lwsl_parser("%s: cached %ld\n", __func__, (long)len);
|
||||
*buf += len; /* stashing it is taking care of it */
|
||||
return 1;
|
||||
}
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
if (wsi->ws->rx_draining_ext) {
|
||||
lwsl_debug("%s: draining rx ext\n", __func__);
|
||||
m = lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR, 0);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* consume payload bytes efficiently */
|
||||
while (wsi->lws_rx_parse_state == LWS_RXPS_WS_FRAME_PAYLOAD &&
|
||||
(wsi->ws->opcode == LWSWSOPC_TEXT_FRAME ||
|
||||
wsi->ws->opcode == LWSWSOPC_BINARY_FRAME ||
|
||||
wsi->ws->opcode == LWSWSOPC_CONTINUATION) &&
|
||||
len) {
|
||||
uint8_t *bin = *buf;
|
||||
|
||||
bulk = 1;
|
||||
m = lws_ws_frame_rest_is_payload(wsi, buf, len);
|
||||
assert((int)lws_ptr_diff(*buf, bin) <= (int)len);
|
||||
len -= lws_ptr_diff(*buf, bin);
|
||||
|
||||
if (!m) {
|
||||
|
||||
break;
|
||||
}
|
||||
if (m < 0) {
|
||||
lwsl_info("%s: rest_is_payload bailed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bulk) {
|
||||
/* process the byte */
|
||||
m = lws_ws_rx_sm(wsi, 0, *(*buf)++);
|
||||
len--;
|
||||
} else {
|
||||
/*
|
||||
* We already handled this byte in bulk, just deal
|
||||
* with the ramifications
|
||||
*/
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
lwsl_debug("%s: coming out of bulk with len %d, "
|
||||
"wsi->ws->rx_draining_ext %d\n",
|
||||
__func__, (int)len,
|
||||
wsi->ws->rx_draining_ext);
|
||||
#endif
|
||||
m = lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR |
|
||||
ALREADY_PROCESSED_NO_CB, 0);
|
||||
}
|
||||
|
||||
if (m < 0) {
|
||||
lwsl_info("%s: lws_ws_rx_sm bailed %d\n", __func__,
|
||||
bulk);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bulk = 0;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: exit with %d unused\n", __func__, (int)len);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - generic hash and HMAC api hiding the backend
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
*
|
||||
* lws_genhash provides a hash / hmac abstraction api in lws that works the
|
||||
* same whether you are using openssl or mbedtls hash functions underneath.
|
||||
*/
|
||||
#include "libwebsockets.h"
|
||||
#include <mbedtls/version.h>
|
||||
|
||||
#if (MBEDTLS_VERSION_NUMBER >= 0x02070000)
|
||||
#define MBA(fn) fn##_ret
|
||||
#else
|
||||
#define MBA(fn) fn
|
||||
#endif
|
||||
|
||||
size_t
|
||||
lws_genhash_size(enum lws_genhash_types type)
|
||||
{
|
||||
switch(type) {
|
||||
case LWS_GENHASH_TYPE_SHA1:
|
||||
return 20;
|
||||
case LWS_GENHASH_TYPE_SHA256:
|
||||
return 32;
|
||||
case LWS_GENHASH_TYPE_SHA384:
|
||||
return 48;
|
||||
case LWS_GENHASH_TYPE_SHA512:
|
||||
return 64;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type)
|
||||
{
|
||||
ctx->type = type;
|
||||
|
||||
switch (ctx->type) {
|
||||
case LWS_GENHASH_TYPE_SHA1:
|
||||
mbedtls_sha1_init(&ctx->u.sha1);
|
||||
MBA(mbedtls_sha1_starts)(&ctx->u.sha1);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA256:
|
||||
mbedtls_sha256_init(&ctx->u.sha256);
|
||||
MBA(mbedtls_sha256_starts)(&ctx->u.sha256, 0);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA384:
|
||||
mbedtls_sha512_init(&ctx->u.sha512);
|
||||
MBA(mbedtls_sha512_starts)(&ctx->u.sha512, 1 /* is384 */);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA512:
|
||||
mbedtls_sha512_init(&ctx->u.sha512);
|
||||
MBA(mbedtls_sha512_starts)(&ctx->u.sha512, 0);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len)
|
||||
{
|
||||
switch (ctx->type) {
|
||||
case LWS_GENHASH_TYPE_SHA1:
|
||||
MBA(mbedtls_sha1_update)(&ctx->u.sha1, in, len);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA256:
|
||||
MBA(mbedtls_sha256_update)(&ctx->u.sha256, in, len);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA384:
|
||||
MBA(mbedtls_sha512_update)(&ctx->u.sha512, in, len);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA512:
|
||||
MBA(mbedtls_sha512_update)(&ctx->u.sha512, in, len);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)
|
||||
{
|
||||
switch (ctx->type) {
|
||||
case LWS_GENHASH_TYPE_SHA1:
|
||||
MBA(mbedtls_sha1_finish)(&ctx->u.sha1, result);
|
||||
mbedtls_sha1_free(&ctx->u.sha1);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA256:
|
||||
MBA(mbedtls_sha256_finish)(&ctx->u.sha256, result);
|
||||
mbedtls_sha256_free(&ctx->u.sha256);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA384:
|
||||
MBA(mbedtls_sha512_finish)(&ctx->u.sha512, result);
|
||||
mbedtls_sha512_free(&ctx->u.sha512);
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA512:
|
||||
MBA(mbedtls_sha512_finish)(&ctx->u.sha512, result);
|
||||
mbedtls_sha512_free(&ctx->u.sha512);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
lws_genhmac_size(enum lws_genhmac_types type)
|
||||
{
|
||||
switch(type) {
|
||||
case LWS_GENHMAC_TYPE_SHA256:
|
||||
return 32;
|
||||
case LWS_GENHMAC_TYPE_SHA384:
|
||||
return 48;
|
||||
case LWS_GENHMAC_TYPE_SHA512:
|
||||
return 64;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
|
||||
const uint8_t *key, size_t key_len)
|
||||
{
|
||||
int t;
|
||||
|
||||
ctx->type = type;
|
||||
|
||||
switch (type) {
|
||||
case LWS_GENHMAC_TYPE_SHA256:
|
||||
t = MBEDTLS_MD_SHA256;
|
||||
break;
|
||||
case LWS_GENHMAC_TYPE_SHA384:
|
||||
t = MBEDTLS_MD_SHA384;
|
||||
break;
|
||||
case LWS_GENHMAC_TYPE_SHA512:
|
||||
t = MBEDTLS_MD_SHA512;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->hmac = mbedtls_md_info_from_type(t);
|
||||
if (!ctx->hmac)
|
||||
return -1;
|
||||
|
||||
if (mbedtls_md_init_ctx(&ctx->ctx, ctx->hmac))
|
||||
return -1;
|
||||
|
||||
if (mbedtls_md_hmac_starts(&ctx->ctx, key, key_len)) {
|
||||
mbedtls_md_free(&ctx->ctx);
|
||||
ctx->hmac = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len)
|
||||
{
|
||||
if (mbedtls_md_hmac_update(&ctx->ctx, in, len))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (result)
|
||||
n = mbedtls_md_hmac_finish(&ctx->ctx, result);
|
||||
|
||||
mbedtls_md_free(&ctx->ctx);
|
||||
ctx->hmac = NULL;
|
||||
if (n)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,329 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - generic RSA api hiding the backend
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
*
|
||||
* lws_genhash provides a hash / hmac abstraction api in lws that works the
|
||||
* same whether you are using openssl or mbedtls hash functions underneath.
|
||||
*/
|
||||
#include "core/private.h"
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++)
|
||||
if (el->e[n].buf)
|
||||
lws_free_set_NULL(el->e[n].buf);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)
|
||||
{
|
||||
int n;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->ctx = lws_zalloc(sizeof(*ctx->ctx), "genrsa");
|
||||
if (!ctx->ctx)
|
||||
return 1;
|
||||
|
||||
mbedtls_rsa_init(ctx->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
|
||||
{
|
||||
mbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] = {
|
||||
&ctx->ctx->E, &ctx->ctx->N, &ctx->ctx->D, &ctx->ctx->P,
|
||||
&ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ,
|
||||
&ctx->ctx->QP,
|
||||
};
|
||||
|
||||
for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++)
|
||||
if (el->e[n].buf &&
|
||||
mbedtls_mpi_read_binary(mpi[n], el->e[n].buf,
|
||||
el->e[n].len)) {
|
||||
lwsl_notice("mpi load failed\n");
|
||||
lws_free_set_NULL(ctx->ctx);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->ctx->len = el->e[JWK_KEY_N].len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_rngf(void *context, unsigned char *buf, size_t len)
|
||||
{
|
||||
if ((size_t)lws_get_random(context, buf, len) == len)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
|
||||
struct lws_genrsa_elements *el, int bits)
|
||||
{
|
||||
int n;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->ctx = lws_zalloc(sizeof(*ctx->ctx), "genrsa");
|
||||
if (!ctx->ctx)
|
||||
return -1;
|
||||
|
||||
mbedtls_rsa_init(ctx->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
|
||||
n = mbedtls_rsa_gen_key(ctx->ctx, _rngf, context, bits, 65537);
|
||||
if (n) {
|
||||
lwsl_err("mbedtls_rsa_gen_key failed 0x%x\n", -n);
|
||||
goto cleanup_1;
|
||||
}
|
||||
|
||||
{
|
||||
mbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] = {
|
||||
&ctx->ctx->E, &ctx->ctx->N, &ctx->ctx->D, &ctx->ctx->P,
|
||||
&ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ,
|
||||
&ctx->ctx->QP,
|
||||
};
|
||||
|
||||
for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++)
|
||||
if (mbedtls_mpi_size(mpi[n])) {
|
||||
el->e[n].buf = lws_malloc(
|
||||
mbedtls_mpi_size(mpi[n]), "genrsakey");
|
||||
if (!el->e[n].buf)
|
||||
goto cleanup;
|
||||
el->e[n].len = mbedtls_mpi_size(mpi[n]);
|
||||
mbedtls_mpi_write_binary(mpi[n], el->e[n].buf,
|
||||
el->e[n].len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++)
|
||||
if (el->e[n].buf)
|
||||
lws_free_set_NULL(el->e[n].buf);
|
||||
cleanup_1:
|
||||
lws_free(ctx->ctx);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
|
||||
size_t in_len, uint8_t *out, size_t out_max)
|
||||
{
|
||||
size_t olen = 0;
|
||||
int n;
|
||||
|
||||
ctx->ctx->len = in_len;
|
||||
n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, NULL, NULL,
|
||||
MBEDTLS_RSA_PUBLIC,
|
||||
&olen, in, out, out_max);
|
||||
if (n) {
|
||||
lwsl_notice("%s: -0x%x\n", __func__, -n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return olen;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
|
||||
size_t in_len, uint8_t *out)
|
||||
{
|
||||
int n;
|
||||
|
||||
ctx->ctx->len = in_len;
|
||||
n = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx->ctx, NULL, NULL,
|
||||
MBEDTLS_RSA_PRIVATE,
|
||||
in_len, in, out);
|
||||
if (n) {
|
||||
lwsl_notice("%s: -0x%x\n", __func__, -n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_genrsa_genrsa_hash_to_mbed_hash(enum lws_genhash_types hash_type)
|
||||
{
|
||||
int h = -1;
|
||||
|
||||
switch (hash_type) {
|
||||
case LWS_GENHASH_TYPE_SHA1:
|
||||
h = MBEDTLS_MD_SHA1;
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA256:
|
||||
h = MBEDTLS_MD_SHA256;
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA384:
|
||||
h = MBEDTLS_MD_SHA384;
|
||||
break;
|
||||
case LWS_GENHASH_TYPE_SHA512:
|
||||
h = MBEDTLS_MD_SHA512;
|
||||
break;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
|
||||
enum lws_genhash_types hash_type, const uint8_t *sig,
|
||||
size_t sig_len)
|
||||
{
|
||||
int n, h = lws_genrsa_genrsa_hash_to_mbed_hash(hash_type);
|
||||
|
||||
if (h < 0)
|
||||
return -1;
|
||||
|
||||
n = mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx->ctx, NULL, NULL,
|
||||
MBEDTLS_RSA_PUBLIC,
|
||||
h, 0, in, sig);
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: -0x%x\n", __func__, -n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_public_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
|
||||
enum lws_genhash_types hash_type, uint8_t *sig,
|
||||
size_t sig_len)
|
||||
{
|
||||
int n, h = lws_genrsa_genrsa_hash_to_mbed_hash(hash_type);
|
||||
|
||||
if (h < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* The "sig" buffer must be as large as the size of ctx->N
|
||||
* (eg. 128 bytes if RSA-1024 is used).
|
||||
*/
|
||||
if (sig_len < ctx->ctx->len)
|
||||
return -1;
|
||||
|
||||
n = mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx->ctx, NULL, NULL,
|
||||
MBEDTLS_RSA_PRIVATE, h, 0, in,
|
||||
sig);
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: -0x%x\n", __func__, -n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ctx->ctx->len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private,
|
||||
uint8_t *pkey_asn1, size_t pkey_asn1_len)
|
||||
{
|
||||
uint8_t *p = pkey_asn1, *totlen, *end = pkey_asn1 + pkey_asn1_len - 1;
|
||||
mbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] = {
|
||||
&ctx->ctx->N, &ctx->ctx->E, &ctx->ctx->D, &ctx->ctx->P,
|
||||
&ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ,
|
||||
&ctx->ctx->QP,
|
||||
};
|
||||
int n;
|
||||
|
||||
/* 30 82 - sequence
|
||||
* 09 29 <-- length(0x0929) less 4 bytes
|
||||
* 02 01 <- length (1)
|
||||
* 00
|
||||
* 02 82
|
||||
* 02 01 <- length (513) N
|
||||
* ...
|
||||
*
|
||||
* 02 03 <- length (3) E
|
||||
* 01 00 01
|
||||
*
|
||||
* 02 82
|
||||
* 02 00 <- length (512) D P Q EXP1 EXP2 COEFF
|
||||
*
|
||||
* */
|
||||
|
||||
*p++ = 0x30;
|
||||
*p++ = 0x82;
|
||||
totlen = p;
|
||||
p += 2;
|
||||
|
||||
*p++ = 0x02;
|
||||
*p++ = 0x01;
|
||||
*p++ = 0x00;
|
||||
|
||||
for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++) {
|
||||
int m = mbedtls_mpi_size(mpi[n]);
|
||||
uint8_t *elen;
|
||||
|
||||
*p++ = 0x02;
|
||||
elen = p;
|
||||
if (m < 0x7f)
|
||||
*p++ = m;
|
||||
else {
|
||||
*p++ = 0x82;
|
||||
*p++ = m >> 8;
|
||||
*p++ = m & 0xff;
|
||||
}
|
||||
|
||||
if (p + m > end)
|
||||
return -1;
|
||||
|
||||
mbedtls_mpi_write_binary(mpi[n], p, m);
|
||||
if (p[0] & 0x80) {
|
||||
p[0] = 0x00;
|
||||
mbedtls_mpi_write_binary(mpi[n], &p[1], m);
|
||||
m++;
|
||||
}
|
||||
if (m < 0x7f)
|
||||
*elen = m;
|
||||
else {
|
||||
*elen++ = 0x82;
|
||||
*elen++ = m >> 8;
|
||||
*elen = m & 0xff;
|
||||
}
|
||||
p += m;
|
||||
}
|
||||
|
||||
n = lws_ptr_diff(p, pkey_asn1);
|
||||
|
||||
*totlen++ = (n - 4) >> 8;
|
||||
*totlen = (n - 4) & 0xff;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_genrsa_destroy(struct lws_genrsa_ctx *ctx)
|
||||
{
|
||||
if (!ctx->ctx)
|
||||
return;
|
||||
mbedtls_rsa_free(ctx->ctx);
|
||||
lws_free(ctx->ctx);
|
||||
ctx->ctx = NULL;
|
||||
}
|
|
@ -1,240 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - mbedtls-specific client TLS code
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
static int
|
||||
OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
{
|
||||
X509_VERIFY_PARAM *param;
|
||||
char hostname[128], *p;
|
||||
const char *alpn_comma = wsi->context->tls.alpn_default;
|
||||
struct alpn_ctx protos;
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
_WSI_TOKEN_CLIENT_HOST) <= 0) {
|
||||
lwsl_err("%s: Unable to get hostname\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove any :port part on the hostname... necessary for network
|
||||
* connection but typical certificates do not contain it
|
||||
*/
|
||||
p = hostname;
|
||||
while (*p) {
|
||||
if (*p == ':') {
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_client_ctx);
|
||||
if (!wsi->tls.ssl)
|
||||
return -1;
|
||||
|
||||
if (wsi->vhost->tls.ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
|
||||
|
||||
if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
|
||||
param = SSL_get0_param(wsi->tls.ssl);
|
||||
/* Enable automatic hostname checks */
|
||||
// X509_VERIFY_PARAM_set_hostflags(param,
|
||||
// X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
X509_VERIFY_PARAM_set1_host(param, hostname, 0);
|
||||
}
|
||||
|
||||
if (wsi->vhost->tls.alpn)
|
||||
alpn_comma = wsi->vhost->tls.alpn;
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
_WSI_TOKEN_CLIENT_ALPN) > 0)
|
||||
alpn_comma = hostname;
|
||||
|
||||
lwsl_info("%s: %p: client conn sending ALPN list '%s'\n",
|
||||
__func__, wsi, alpn_comma);
|
||||
|
||||
protos.len = lws_alpn_comma_to_openssl(alpn_comma, protos.data,
|
||||
sizeof(protos.data) - 1);
|
||||
|
||||
/* with mbedtls, protos is not pointed to after exit from this call */
|
||||
SSL_set_alpn_select_cb(wsi->tls.ssl, &protos);
|
||||
|
||||
/*
|
||||
* use server name indication (SNI), if supported,
|
||||
* when establishing connection
|
||||
*/
|
||||
SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER,
|
||||
OpenSSL_client_verify_callback);
|
||||
|
||||
SSL_set_fd(wsi->tls.ssl, wsi->desc.sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ERR_get_error(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum lws_ssl_capable_status
|
||||
lws_tls_client_connect(struct lws *wsi)
|
||||
{
|
||||
int m, n = SSL_connect(wsi->tls.ssl);
|
||||
const unsigned char *prot;
|
||||
unsigned int len;
|
||||
|
||||
if (n == 1) {
|
||||
SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
|
||||
lws_role_call_alpn_negotiated(wsi, (const char *)prot);
|
||||
lwsl_info("client connect OK\n");
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
||||
m = SSL_get_error(wsi->tls.ssl, n);
|
||||
|
||||
if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
|
||||
|
||||
if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
|
||||
|
||||
if (!n) /* we don't know what he wants, but he says to retry */
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
|
||||
{
|
||||
int n;
|
||||
X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl);
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char *sb = (char *)&pt->serv_buf[0];
|
||||
|
||||
if (!peer) {
|
||||
lwsl_info("peer did not provide cert\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
lwsl_info("peer provided cert\n");
|
||||
|
||||
n = SSL_get_verify_result(wsi->tls.ssl);
|
||||
lws_latency(wsi->context, wsi,
|
||||
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
|
||||
|
||||
lwsl_debug("get_verify says %d\n", n);
|
||||
|
||||
if (n == X509_V_OK)
|
||||
return 0;
|
||||
|
||||
if (n == X509_V_ERR_HOSTNAME_MISMATCH &&
|
||||
(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
|
||||
lwsl_info("accepting certificate for invalid hostname\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n == X509_V_ERR_INVALID_CA &&
|
||||
(wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
|
||||
lwsl_info("accepting certificate from untrusted CA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
|
||||
n == X509_V_ERR_CERT_HAS_EXPIRED) &&
|
||||
(wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED)) {
|
||||
lwsl_info("accepting expired or not yet valid certificate\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
lws_snprintf(ebuf, ebuf_len,
|
||||
"server's cert didn't look good, X509_V_ERR = %d: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
lwsl_info("%s\n", ebuf);
|
||||
lws_ssl_elaborate_error();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_client_create_vhost_context(struct lws_vhost *vh,
|
||||
const struct lws_context_creation_info *info,
|
||||
const char *cipher_list,
|
||||
const char *ca_filepath,
|
||||
const char *cert_filepath,
|
||||
const char *private_key_filepath)
|
||||
{
|
||||
X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
|
||||
SSL_METHOD *method = (SSL_METHOD *)TLS_client_method();
|
||||
unsigned long error;
|
||||
lws_filepos_t len;
|
||||
uint8_t *buf;
|
||||
|
||||
if (!method) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl method %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)vh->context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
/* create context */
|
||||
vh->tls.ssl_client_ctx = SSL_CTX_new(method);
|
||||
if (!vh->tls.ssl_client_ctx) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl context %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)vh->context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ca_filepath)
|
||||
return 0;
|
||||
|
||||
if (alloc_file(vh->context, ca_filepath, &buf, &len)) {
|
||||
lwsl_err("Load CA cert file %s failed\n", ca_filepath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vh->tls.x509_client_CA = d2i_X509(NULL, buf, len);
|
||||
free(buf);
|
||||
if (!vh->tls.x509_client_CA) {
|
||||
lwsl_err("client CA: x509 parse failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!vh->tls.ssl_ctx)
|
||||
SSL_CTX_add_client_CA(vh->tls.ssl_client_ctx, vh->tls.x509_client_CA);
|
||||
else
|
||||
SSL_CTX_add_client_CA(vh->tls.ssl_ctx, vh->tls.x509_client_CA);
|
||||
|
||||
lwsl_notice("client loaded CA for verification %s\n", ca_filepath);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,694 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - mbedTLS-specific server functions
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
#include <mbedtls/x509_csr.h>
|
||||
|
||||
int
|
||||
lws_tls_server_client_cert_verify_config(struct lws_vhost *vh)
|
||||
{
|
||||
int verify_options = SSL_VERIFY_PEER;
|
||||
|
||||
/* as a server, are we requiring clients to identify themselves? */
|
||||
if (!lws_check_opt(vh->options,
|
||||
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {
|
||||
lwsl_notice("no client cert required\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The wrapper has this messed-up mapping:
|
||||
*
|
||||
* else if (ctx->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
|
||||
* mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
*
|
||||
* ie the meaning is inverted. So where we should test for ! we don't
|
||||
*/
|
||||
if (lws_check_opt(vh->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
|
||||
verify_options = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||
|
||||
lwsl_notice("%s: vh %s requires client cert %d\n", __func__, vh->name,
|
||||
verify_options);
|
||||
|
||||
SSL_CTX_set_verify(vh->tls.ssl_ctx, verify_options, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_mbedtls_sni_cb(void *arg, mbedtls_ssl_context *mbedtls_ctx,
|
||||
const unsigned char *servername, size_t len)
|
||||
{
|
||||
SSL *ssl = SSL_SSL_from_mbedtls_ssl_context(mbedtls_ctx);
|
||||
struct lws_context *context = (struct lws_context *)arg;
|
||||
struct lws_vhost *vhost, *vh;
|
||||
|
||||
lwsl_notice("%s: %s\n", __func__, servername);
|
||||
|
||||
/*
|
||||
* We can only get ssl accepted connections by using a vhost's ssl_ctx
|
||||
* find out which listening one took us and only match vhosts on the
|
||||
* same port.
|
||||
*/
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
if (!vh->being_destroyed &&
|
||||
vh->tls.ssl_ctx == SSL_get_SSL_CTX(ssl))
|
||||
break;
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (!vh) {
|
||||
assert(vh); /* can't match the incoming vh? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
vhost = lws_select_vhost(context, vh->listen_port,
|
||||
(const char *)servername);
|
||||
if (!vhost) {
|
||||
lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_info("SNI: Found: %s:%d at vhost '%s'\n", servername,
|
||||
vh->listen_port, vhost->name);
|
||||
|
||||
/* select the ssl ctx from the selected vhost for this conn */
|
||||
SSL_set_SSL_CTX(ssl, vhost->tls.ssl_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
|
||||
const char *cert, const char *private_key,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t mem_privkey_len)
|
||||
{
|
||||
int n, f = 0;
|
||||
const char *filepath = private_key;
|
||||
uint8_t *mem = NULL, *p = NULL;
|
||||
size_t mem_len = 0;
|
||||
lws_filepos_t flen;
|
||||
long err;
|
||||
|
||||
if ((!cert || !private_key) && (!mem_cert || !mem_privkey)) {
|
||||
lwsl_notice("%s: no usable input\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = lws_tls_generic_cert_checks(vhost, cert, private_key);
|
||||
|
||||
if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* we can't read the root-privs files. But if mem_cert is provided,
|
||||
* we should use that.
|
||||
*/
|
||||
if (n == LWS_TLS_EXTANT_NO)
|
||||
n = LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
|
||||
if (n == LWS_TLS_EXTANT_ALTERNATIVE && (!mem_cert || !mem_privkey))
|
||||
return 1; /* no alternative */
|
||||
|
||||
if (n == LWS_TLS_EXTANT_ALTERNATIVE) {
|
||||
/*
|
||||
* Although we have prepared update certs, we no longer have
|
||||
* the rights to read our own cert + key we saved.
|
||||
*
|
||||
* If we were passed copies in memory buffers, use those
|
||||
* instead.
|
||||
*
|
||||
* The passed memory-buffer cert image is in DER, and the
|
||||
* memory-buffer private key image is PEM.
|
||||
*/
|
||||
/* mem cert is already DER */
|
||||
p = (uint8_t *)mem_cert;
|
||||
flen = len_mem_cert;
|
||||
/* mem private key is PEM, so go through the motions */
|
||||
mem = (uint8_t *)mem_privkey;
|
||||
mem_len = mem_privkey_len;
|
||||
filepath = NULL;
|
||||
} else {
|
||||
if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, NULL,
|
||||
0, &p, &flen)) {
|
||||
lwsl_err("couldn't find cert file %s\n", cert);
|
||||
|
||||
return 1;
|
||||
}
|
||||
f = 1;
|
||||
}
|
||||
err = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, flen, p);
|
||||
if (!err) {
|
||||
free(p);
|
||||
lwsl_err("Problem loading cert\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f)
|
||||
free(p);
|
||||
p = NULL;
|
||||
|
||||
if (private_key || n == LWS_TLS_EXTANT_ALTERNATIVE) {
|
||||
if (lws_tls_alloc_pem_to_der_file(vhost->context, filepath,
|
||||
(char *)mem, mem_len, &p,
|
||||
&flen)) {
|
||||
lwsl_err("couldn't find private key file %s\n",
|
||||
private_key);
|
||||
|
||||
return 1;
|
||||
}
|
||||
err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->tls.ssl_ctx, p, flen);
|
||||
if (!err) {
|
||||
free(p);
|
||||
lwsl_err("Problem loading key\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (p && !mem_privkey) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if (!private_key && !mem_privkey &&
|
||||
vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
|
||||
vhost->tls.ssl_ctx, NULL, 0)) {
|
||||
lwsl_err("ssl private key not set\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
vhost->tls.skipped_certs = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost, struct lws *wsi)
|
||||
{
|
||||
const SSL_METHOD *method = TLS_server_method();
|
||||
uint8_t *p;
|
||||
lws_filepos_t flen;
|
||||
int n;
|
||||
|
||||
vhost->tls.ssl_ctx = SSL_CTX_new(method); /* create context */
|
||||
if (!vhost->tls.ssl_ctx) {
|
||||
lwsl_err("problem creating ssl context\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!vhost->tls.use_ssl || !info->ssl_cert_filepath)
|
||||
return 0;
|
||||
|
||||
if (info->ssl_ca_filepath) {
|
||||
lwsl_notice("%s: vh %s: loading CA filepath %s\n", __func__,
|
||||
vhost->name, info->ssl_ca_filepath);
|
||||
if (lws_tls_alloc_pem_to_der_file(vhost->context,
|
||||
info->ssl_ca_filepath, NULL, 0, &p, &flen)) {
|
||||
lwsl_err("couldn't find client CA file %s\n",
|
||||
info->ssl_ca_filepath);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_add_client_CA_ASN1(vhost->tls.ssl_ctx, (int)flen, p) != 1) {
|
||||
lwsl_err("%s: SSL_CTX_add_client_CA_ASN1 unhappy\n",
|
||||
__func__);
|
||||
free(p);
|
||||
return 1;
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
|
||||
n = lws_tls_server_certs_load(vhost, wsi, info->ssl_cert_filepath,
|
||||
info->ssl_private_key_filepath, NULL,
|
||||
0, NULL, 0);
|
||||
if (n)
|
||||
return n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
|
||||
{
|
||||
errno = 0;
|
||||
wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_ctx);
|
||||
if (wsi->tls.ssl == NULL) {
|
||||
lwsl_err("SSL_new failed: errno %d\n", errno);
|
||||
|
||||
lws_ssl_elaborate_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
SSL_set_fd(wsi->tls.ssl, accept_fd);
|
||||
|
||||
if (wsi->vhost->tls.ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
|
||||
|
||||
SSL_set_sni_callback(wsi->tls.ssl, lws_mbedtls_sni_cb, wsi->context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_server_abort_connection(struct lws *wsi)
|
||||
{
|
||||
__lws_tls_shutdown(wsi);
|
||||
SSL_free(wsi->tls.ssl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum lws_ssl_capable_status
|
||||
lws_tls_server_accept(struct lws *wsi)
|
||||
{
|
||||
union lws_tls_cert_info_results ir;
|
||||
int m, n;
|
||||
|
||||
n = SSL_accept(wsi->tls.ssl);
|
||||
if (n == 1) {
|
||||
|
||||
if (strstr(wsi->vhost->name, ".invalid")) {
|
||||
lwsl_notice("%s: vhost has .invalid, rejecting accept\n", __func__);
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir,
|
||||
sizeof(ir.ns.name));
|
||||
if (!n)
|
||||
lwsl_notice("%s: client cert CN '%s'\n",
|
||||
__func__, ir.ns.name);
|
||||
else
|
||||
lwsl_info("%s: couldn't get client cert CN\n", __func__);
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
||||
m = SSL_get_error(wsi->tls.ssl, n);
|
||||
lwsl_debug("%s: %p: accept SSL_get_error %d errno %d\n", __func__,
|
||||
wsi, m, errno);
|
||||
|
||||
// mbedtls wrapper only
|
||||
if (m == SSL_ERROR_SYSCALL && errno == 11)
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
|
||||
|
||||
if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
|
||||
lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
lwsl_info("SSL_ERROR_WANT_READ\n");
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
|
||||
}
|
||||
if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
|
||||
lwsl_debug("%s: WANT_WRITE\n", __func__);
|
||||
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
|
||||
lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
|
||||
}
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_ACME)
|
||||
/*
|
||||
* mbedtls doesn't support SAN for cert creation. So we use a known-good
|
||||
* tls-sni-01 cert from OpenSSL that worked on Let's Encrypt, and just replace
|
||||
* the pubkey n part and the signature part.
|
||||
*
|
||||
* This will need redoing for tls-sni-02...
|
||||
*/
|
||||
|
||||
static uint8_t ss_cert_leadin[] = {
|
||||
0x30, 0x82,
|
||||
0x05, 0x56, /* total length: LEN1 (+2 / +3) (correct for 513 + 512)*/
|
||||
|
||||
0x30, 0x82, /* length: LEN2 (+6 / +7) (correct for 513) */
|
||||
0x03, 0x3e,
|
||||
|
||||
/* addition: v3 cert (+5 bytes)*/
|
||||
0xa0, 0x03,
|
||||
0x02, 0x01, 0x02,
|
||||
|
||||
0x02, 0x01, 0x01,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a,
|
||||
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3f,
|
||||
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
|
||||
0x42, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b,
|
||||
0x73, 0x6f, 0x6d, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31,
|
||||
0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x74, 0x65,
|
||||
0x6d, 0x70, 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x76, 0x61,
|
||||
0x6c, 0x69, 0x64, 0x30, 0x1e, 0x17, 0x0d,
|
||||
|
||||
/* from 2017-10-29 ... */
|
||||
0x31, 0x37, 0x31, 0x30, 0x32, 0x39, 0x31, 0x31, 0x34, 0x39, 0x34, 0x35,
|
||||
0x5a, 0x17, 0x0d,
|
||||
|
||||
/* thru 2049-10-29 we immediately discard the private key, no worries */
|
||||
0x34, 0x39, 0x31, 0x30, 0x32, 0x39, 0x31, 0x32, 0x34, 0x39, 0x34, 0x35,
|
||||
0x5a,
|
||||
|
||||
0x30, 0x3f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
||||
0x02, 0x47, 0x42, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
||||
0x0c, 0x0b, 0x73, 0x6f, 0x6d, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e,
|
||||
0x79, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11,
|
||||
0x74, 0x65, 0x6d, 0x70, 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x69, 0x6e,
|
||||
0x76, 0x61, 0x6c, 0x69, 0x64, 0x30,
|
||||
|
||||
0x82,
|
||||
0x02, 0x22, /* LEN3 (+C3 / C4) */
|
||||
0x30, 0x0d, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
|
||||
0x03,
|
||||
|
||||
0x82,
|
||||
0x02, 0x0f, /* LEN4 (+D6 / D7) */
|
||||
|
||||
0x00, 0x30, 0x82,
|
||||
|
||||
0x02, 0x0a, /* LEN5 (+ DB / DC) */
|
||||
|
||||
0x02, 0x82,
|
||||
|
||||
//0x02, 0x01, /* length of n in bytes (including leading 00 if any) */
|
||||
},
|
||||
|
||||
/* 1 + (keybits / 8) bytes N */
|
||||
|
||||
ss_cert_san_leadin[] = {
|
||||
/* e - fixed */
|
||||
0x02, 0x03, 0x01, 0x00, 0x01,
|
||||
|
||||
0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x59, 0x06, 0x03, 0x55, 0x1d,
|
||||
0x11, 0x04, 0x52, 0x30, 0x50, /* <-- SAN length + 2 */
|
||||
|
||||
0x82, 0x4e, /* <-- SAN length */
|
||||
},
|
||||
|
||||
/* 78 bytes of SAN (tls-sni-01)
|
||||
0x61, 0x64, 0x34, 0x31, 0x61, 0x66, 0x62, 0x65, 0x30, 0x63, 0x61, 0x34,
|
||||
0x36, 0x34, 0x32, 0x66, 0x30, 0x61, 0x34, 0x34, 0x39, 0x64, 0x39, 0x63,
|
||||
0x61, 0x37, 0x36, 0x65, 0x62, 0x61, 0x61, 0x62, 0x2e, 0x32, 0x38, 0x39,
|
||||
0x34, 0x64, 0x34, 0x31, 0x36, 0x63, 0x39, 0x38, 0x33, 0x66, 0x31, 0x32,
|
||||
0x65, 0x64, 0x37, 0x33, 0x31, 0x61, 0x33, 0x30, 0x66, 0x35, 0x63, 0x34,
|
||||
0x34, 0x37, 0x37, 0x66, 0x65, 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x69,
|
||||
0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, */
|
||||
|
||||
/* end of LEN2 area */
|
||||
|
||||
ss_cert_sig_leadin[] = {
|
||||
/* it's saying that the signature is SHA256 + RSA */
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
||||
0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
|
||||
|
||||
0x82,
|
||||
0x02, 0x01,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* (keybits / 8) bytes signature to end of LEN1 area */
|
||||
|
||||
#define SAN_A_LENGTH 78
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
|
||||
const char *san_b)
|
||||
{
|
||||
int buflen = 0x560;
|
||||
uint8_t *buf = lws_malloc(buflen, "tmp cert buf"), *p = buf, *pkey_asn1;
|
||||
struct lws_genrsa_ctx ctx;
|
||||
struct lws_genrsa_elements el;
|
||||
uint8_t digest[32];
|
||||
struct lws_genhash_ctx hash_ctx;
|
||||
int pkey_asn1_len = 3 * 1024;
|
||||
int n, m, keybits = lws_plat_recommended_rsa_bits(), adj;
|
||||
|
||||
if (!buf)
|
||||
return 1;
|
||||
|
||||
n = lws_genrsa_new_keypair(vhost->context, &ctx, &el, keybits);
|
||||
if (n < 0) {
|
||||
lws_jwk_destroy_genrsa_elements(&el);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
n = sizeof(ss_cert_leadin);
|
||||
memcpy(p, ss_cert_leadin, n);
|
||||
p += n;
|
||||
|
||||
adj = (0x0556 - 0x401) + (keybits / 4) + 1;
|
||||
buf[2] = adj >> 8;
|
||||
buf[3] = adj & 0xff;
|
||||
|
||||
adj = (0x033e - 0x201) + (keybits / 8) + 1;
|
||||
buf[6] = adj >> 8;
|
||||
buf[7] = adj & 0xff;
|
||||
|
||||
adj = (0x0222 - 0x201) + (keybits / 8) + 1;
|
||||
buf[0xc3] = adj >> 8;
|
||||
buf[0xc4] = adj & 0xff;
|
||||
|
||||
adj = (0x020f - 0x201) + (keybits / 8) + 1;
|
||||
buf[0xd6] = adj >> 8;
|
||||
buf[0xd7] = adj & 0xff;
|
||||
|
||||
adj = (0x020a - 0x201) + (keybits / 8) + 1;
|
||||
buf[0xdb] = adj >> 8;
|
||||
buf[0xdc] = adj & 0xff;
|
||||
|
||||
*p++ = ((keybits / 8) + 1) >> 8;
|
||||
*p++ = ((keybits / 8) + 1) & 0xff;
|
||||
|
||||
/* we need to drop 1 + (keybits / 8) bytes of n in here, 00 + key */
|
||||
|
||||
*p++ = 0x00;
|
||||
memcpy(p, el.e[JWK_KEY_N].buf, el.e[JWK_KEY_N].len);
|
||||
p += el.e[JWK_KEY_N].len;
|
||||
|
||||
memcpy(p, ss_cert_san_leadin, sizeof(ss_cert_san_leadin));
|
||||
p += sizeof(ss_cert_san_leadin);
|
||||
|
||||
/* drop in 78 bytes of san_a */
|
||||
|
||||
memcpy(p, san_a, SAN_A_LENGTH);
|
||||
p += SAN_A_LENGTH;
|
||||
memcpy(p, ss_cert_sig_leadin, sizeof(ss_cert_sig_leadin));
|
||||
|
||||
p[17] = ((keybits / 8) + 1) >> 8;
|
||||
p[18] = ((keybits / 8) + 1) & 0xff;
|
||||
|
||||
p += sizeof(ss_cert_sig_leadin);
|
||||
|
||||
/* hash the cert plaintext */
|
||||
|
||||
if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
|
||||
goto bail2;
|
||||
|
||||
if (lws_genhash_update(&hash_ctx, buf, lws_ptr_diff(p, buf))) {
|
||||
lws_genhash_destroy(&hash_ctx, NULL);
|
||||
|
||||
goto bail2;
|
||||
}
|
||||
if (lws_genhash_destroy(&hash_ctx, digest))
|
||||
goto bail2;
|
||||
|
||||
/* sign the hash */
|
||||
|
||||
n = lws_genrsa_public_sign(&ctx, digest, LWS_GENHASH_TYPE_SHA256, p,
|
||||
buflen - lws_ptr_diff(p, buf));
|
||||
if (n < 0)
|
||||
goto bail2;
|
||||
p += n;
|
||||
|
||||
pkey_asn1 = lws_malloc(pkey_asn1_len, "mbed crt tmp");
|
||||
if (!pkey_asn1)
|
||||
goto bail2;
|
||||
|
||||
m = lws_genrsa_render_pkey_asn1(&ctx, 1, pkey_asn1, pkey_asn1_len);
|
||||
if (m < 0) {
|
||||
lws_free(pkey_asn1);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
// lwsl_hexdump_level(LLL_DEBUG, buf, lws_ptr_diff(p, buf));
|
||||
n = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx,
|
||||
lws_ptr_diff(p, buf), buf);
|
||||
if (n != 1) {
|
||||
lws_free(pkey_asn1);
|
||||
lwsl_err("%s: generated cert failed to load 0x%x\n",
|
||||
__func__, -n);
|
||||
} else {
|
||||
//lwsl_debug("private key\n");
|
||||
//lwsl_hexdump_level(LLL_DEBUG, pkey_asn1, n);
|
||||
|
||||
/* and to use our generated private key */
|
||||
n = SSL_CTX_use_PrivateKey_ASN1(0, vhost->tls.ssl_ctx, pkey_asn1, m);
|
||||
lws_free(pkey_asn1);
|
||||
if (n != 1) {
|
||||
lwsl_err("%s: SSL_CTX_use_PrivateKey_ASN1 failed\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
|
||||
lws_genrsa_destroy(&ctx);
|
||||
lws_jwk_destroy_genrsa_elements(&el);
|
||||
|
||||
lws_free(buf);
|
||||
|
||||
return n != 1;
|
||||
|
||||
bail2:
|
||||
lws_genrsa_destroy(&ctx);
|
||||
lws_jwk_destroy_genrsa_elements(&el);
|
||||
bail1:
|
||||
lws_free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_JWS)
|
||||
static int
|
||||
_rngf(void *context, unsigned char *buf, size_t len)
|
||||
{
|
||||
if ((size_t)lws_get_random(context, buf, len) == len)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *x5[] = { "C", "ST", "L", "O", "CN" };
|
||||
|
||||
/*
|
||||
* CSR is output formatted as b64url(DER)
|
||||
* Private key is output as a PEM in memory
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
|
||||
uint8_t *dcsr, size_t csr_len, char **privkey_pem,
|
||||
size_t *privkey_len)
|
||||
{
|
||||
mbedtls_x509write_csr csr;
|
||||
mbedtls_pk_context mpk;
|
||||
int buf_size = 4096, n;
|
||||
char subject[200], *p = subject, *end = p + sizeof(subject) - 1;
|
||||
uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
mbedtls_x509write_csr_init(&csr);
|
||||
|
||||
mbedtls_pk_init(&mpk);
|
||||
if (mbedtls_pk_setup(&mpk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) {
|
||||
lwsl_notice("%s: pk_setup failed\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n = mbedtls_rsa_gen_key(mbedtls_pk_rsa(mpk), _rngf, context,
|
||||
lws_plat_recommended_rsa_bits(), 65537);
|
||||
if (n) {
|
||||
lwsl_notice("%s: failed to generate keys\n", __func__);
|
||||
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(x5); n++) {
|
||||
if (p != subject)
|
||||
*p++ = ',';
|
||||
if (elements[n])
|
||||
p += lws_snprintf(p, end - p, "%s=%s", x5[n],
|
||||
elements[n]);
|
||||
}
|
||||
|
||||
if (mbedtls_x509write_csr_set_subject_name(&csr, subject))
|
||||
goto fail1;
|
||||
|
||||
mbedtls_x509write_csr_set_key(&csr, &mpk);
|
||||
mbedtls_x509write_csr_set_md_alg(&csr, MBEDTLS_MD_SHA256);
|
||||
|
||||
/*
|
||||
* data is written at the end of the buffer! Use the
|
||||
* return value to determine where you should start
|
||||
* using the buffer
|
||||
*/
|
||||
n = mbedtls_x509write_csr_der(&csr, buf, buf_size, _rngf, context);
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: write csr der failed\n", __func__);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* we have it in DER, we need it in b64URL */
|
||||
|
||||
n = lws_jws_base64_enc((char *)(buf + buf_size) - n, n,
|
||||
(char *)dcsr, csr_len);
|
||||
if (n < 0)
|
||||
goto fail1;
|
||||
|
||||
/*
|
||||
* okay, the CSR is done, last we need the private key in PEM
|
||||
* re-use the DER CSR buf as the result buffer since we cn do it in
|
||||
* one step
|
||||
*/
|
||||
|
||||
if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
|
||||
lwsl_notice("write key pem failed\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
*privkey_pem = (char *)buf;
|
||||
*privkey_len = strlen((const char *)buf);
|
||||
|
||||
mbedtls_pk_free(&mpk);
|
||||
mbedtls_x509write_csr_free(&csr);
|
||||
|
||||
return n;
|
||||
|
||||
fail1:
|
||||
mbedtls_pk_free(&mpk);
|
||||
fail:
|
||||
mbedtls_x509write_csr_free(&csr);
|
||||
free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,518 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - mbedTLS-specific lws apis
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
#include <mbedtls/oid.h>
|
||||
|
||||
void
|
||||
lws_ssl_elaborate_error(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info)
|
||||
{
|
||||
lwsl_info(" Compiled with MbedTLS support\n");
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
lwsl_info(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
if (!lws_check_opt(vhost->context->options,
|
||||
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
return;
|
||||
|
||||
if (vhost->tls.ssl_ctx)
|
||||
SSL_CTX_free(vhost->tls.ssl_ctx);
|
||||
if (!vhost->tls.user_supplied_ssl_ctx && vhost->tls.ssl_client_ctx)
|
||||
SSL_CTX_free(vhost->tls.ssl_client_ctx);
|
||||
|
||||
if (vhost->tls.x509_client_CA)
|
||||
X509_free(vhost->tls.x509_client_CA);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n = 0, m;
|
||||
|
||||
if (!wsi->tls.ssl)
|
||||
return lws_ssl_capable_read_no_ssl(wsi, buf, len);
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
|
||||
|
||||
errno = 0;
|
||||
n = SSL_read(wsi->tls.ssl, buf, len);
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
if (!n && errno == ENOTCONN) {
|
||||
lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->seen_rx) {
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_MS_SSL_RX_DELAY,
|
||||
time_in_microseconds() - wsi->accept_start_us);
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
|
||||
wsi->seen_rx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
lwsl_debug("%p: SSL_read says %d\n", wsi, n);
|
||||
/* manpage: returning 0 means connection shut down */
|
||||
if (!n) {
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
m = SSL_get_error(wsi->tls.ssl, n);
|
||||
lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno);
|
||||
if (m == SSL_ERROR_ZERO_RETURN ||
|
||||
m == SSL_ERROR_SYSCALL)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
|
||||
lwsl_debug("%s: WANT_READ\n", __func__);
|
||||
lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
|
||||
lwsl_debug("%s: WANT_WRITE\n", __func__);
|
||||
lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
|
||||
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->conn_stats.rx += n;
|
||||
|
||||
/*
|
||||
* if it was our buffer that limited what we read,
|
||||
* check if SSL has additional data pending inside SSL buffers.
|
||||
*
|
||||
* Because these won't signal at the network layer with POLLIN
|
||||
* and if we don't realize, this data will sit there forever
|
||||
*/
|
||||
if (n != len)
|
||||
goto bail;
|
||||
if (!wsi->tls.ssl)
|
||||
goto bail;
|
||||
|
||||
if (!SSL_pending(wsi->tls.ssl))
|
||||
goto bail;
|
||||
|
||||
if (wsi->tls.pending_read_list_next)
|
||||
return n;
|
||||
if (wsi->tls.pending_read_list_prev)
|
||||
return n;
|
||||
if (pt->tls.pending_read_list == wsi)
|
||||
return n;
|
||||
|
||||
/* add us to the linked list of guys with pending ssl */
|
||||
if (pt->tls.pending_read_list)
|
||||
pt->tls.pending_read_list->tls.pending_read_list_prev = wsi;
|
||||
|
||||
wsi->tls.pending_read_list_next = pt->tls.pending_read_list;
|
||||
wsi->tls.pending_read_list_prev = NULL;
|
||||
pt->tls.pending_read_list = wsi;
|
||||
|
||||
return n;
|
||||
bail:
|
||||
lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_pending(struct lws *wsi)
|
||||
{
|
||||
if (!wsi->tls.ssl)
|
||||
return 0;
|
||||
|
||||
return SSL_pending(wsi->tls.ssl);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n, m;
|
||||
|
||||
if (!wsi->tls.ssl)
|
||||
return lws_ssl_capable_write_no_ssl(wsi, buf, len);
|
||||
|
||||
n = SSL_write(wsi->tls.ssl, buf, len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
|
||||
m = SSL_get_error(wsi->tls.ssl, n);
|
||||
if (m != SSL_ERROR_SYSCALL) {
|
||||
if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
|
||||
lwsl_notice("%s: want read\n", __func__);
|
||||
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
|
||||
if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
|
||||
lws_set_blocking_send(wsi);
|
||||
lwsl_notice("%s: want write\n", __func__);
|
||||
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_debug("%s failed: %d\n",__func__, m);
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
int openssl_SSL_CTX_private_data_index;
|
||||
|
||||
void
|
||||
lws_ssl_info_callback(const SSL *ssl, int where, int ret)
|
||||
{
|
||||
struct lws *wsi;
|
||||
struct lws_context *context;
|
||||
struct lws_ssl_info si;
|
||||
|
||||
context = (struct lws_context *)SSL_CTX_get_ex_data(
|
||||
SSL_get_SSL_CTX(ssl),
|
||||
openssl_SSL_CTX_private_data_index);
|
||||
if (!context)
|
||||
return;
|
||||
wsi = wsi_from_fd(context, SSL_get_fd(ssl));
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
if (!(where & wsi->vhost->tls.ssl_info_event_mask))
|
||||
return;
|
||||
|
||||
si.where = where;
|
||||
si.ret = ret;
|
||||
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_SSL_INFO,
|
||||
wsi->user_space, &si, 0))
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_close(struct lws *wsi)
|
||||
{
|
||||
lws_sockfd_type n;
|
||||
|
||||
if (!wsi->tls.ssl)
|
||||
return 0; /* not handled */
|
||||
|
||||
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
/* kill ssl callbacks, becausse we will remove the fd from the
|
||||
* table linking it to the wsi
|
||||
*/
|
||||
if (wsi->vhost->tls.ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->tls.ssl, NULL);
|
||||
#endif
|
||||
|
||||
n = SSL_get_fd(wsi->tls.ssl);
|
||||
if (!wsi->socket_is_permanently_unusable)
|
||||
SSL_shutdown(wsi->tls.ssl);
|
||||
compatible_close(n);
|
||||
SSL_free(wsi->tls.ssl);
|
||||
wsi->tls.ssl = NULL;
|
||||
|
||||
if (!lwsi_role_client(wsi) &&
|
||||
wsi->context->simultaneous_ssl_restriction &&
|
||||
wsi->context->simultaneous_ssl-- ==
|
||||
wsi->context->simultaneous_ssl_restriction)
|
||||
/* we made space and can do an accept */
|
||||
lws_gate_accepts(wsi->context, 1);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
wsi->context->updated = 1;
|
||||
#endif
|
||||
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
if (vhost->tls.ssl_ctx)
|
||||
SSL_CTX_free(vhost->tls.ssl_ctx);
|
||||
|
||||
if (!vhost->tls.user_supplied_ssl_ctx && vhost->tls.ssl_client_ctx)
|
||||
SSL_CTX_free(vhost->tls.ssl_client_ctx);
|
||||
#if defined(LWS_WITH_ACME)
|
||||
lws_tls_acme_sni_cert_destroy(vhost);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_context_destroy(struct lws_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
lws_tls_ctx *
|
||||
lws_tls_ctx_from_wsi(struct lws *wsi)
|
||||
{
|
||||
if (!wsi->tls.ssl)
|
||||
return NULL;
|
||||
|
||||
return SSL_get_SSL_CTX(wsi->tls.ssl);
|
||||
}
|
||||
|
||||
enum lws_ssl_capable_status
|
||||
__lws_tls_shutdown(struct lws *wsi)
|
||||
{
|
||||
int n = SSL_shutdown(wsi->tls.ssl);
|
||||
|
||||
lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
|
||||
|
||||
switch (n) {
|
||||
case 1: /* successful completion */
|
||||
n = shutdown(wsi->desc.sockfd, SHUT_WR);
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
|
||||
case 0: /* needs a retry */
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
default: /* fatal error, or WANT */
|
||||
n = SSL_get_error(wsi->tls.ssl, n);
|
||||
if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
|
||||
if (SSL_want_read(wsi->tls.ssl)) {
|
||||
lwsl_debug("(wants read)\n");
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
|
||||
}
|
||||
if (SSL_want_write(wsi->tls.ssl)) {
|
||||
lwsl_debug("(wants write)\n");
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLOUT);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
|
||||
}
|
||||
}
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static time_t
|
||||
lws_tls_mbedtls_time_to_unix(mbedtls_x509_time *xtime)
|
||||
{
|
||||
struct tm t;
|
||||
|
||||
if (!xtime || !xtime->year || xtime->year < 0)
|
||||
return (time_t)(long long)-1;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
t.tm_year = xtime->year - 1900;
|
||||
t.tm_mon = xtime->mon - 1; /* mbedtls months are 1+, tm are 0+ */
|
||||
t.tm_mday = xtime->day - 1; /* mbedtls days are 1+, tm are 0+ */
|
||||
t.tm_hour = xtime->hour;
|
||||
t.tm_min = xtime->min;
|
||||
t.tm_sec = xtime->sec;
|
||||
t.tm_isdst = -1;
|
||||
|
||||
return mktime(&t);
|
||||
}
|
||||
|
||||
static int
|
||||
lws_tls_mbedtls_get_x509_name(mbedtls_x509_name *name,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
{
|
||||
while (name) {
|
||||
if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid)) {
|
||||
name = name->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len - 1 < name->val.len)
|
||||
return -1;
|
||||
|
||||
memcpy(&buf->ns.name[0], name->val.p, name->val.len);
|
||||
buf->ns.name[name->val.len] = '\0';
|
||||
buf->ns.len = name->val.len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
{
|
||||
if (!x509)
|
||||
return -1;
|
||||
|
||||
switch (type) {
|
||||
case LWS_TLS_CERT_INFO_VALIDITY_FROM:
|
||||
buf->time = lws_tls_mbedtls_time_to_unix(&x509->valid_from);
|
||||
if (buf->time == (time_t)(long long)-1)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_TLS_CERT_INFO_VALIDITY_TO:
|
||||
buf->time = lws_tls_mbedtls_time_to_unix(&x509->valid_to);
|
||||
if (buf->time == (time_t)(long long)-1)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_TLS_CERT_INFO_COMMON_NAME:
|
||||
return lws_tls_mbedtls_get_x509_name(&x509->subject, buf, len);
|
||||
|
||||
case LWS_TLS_CERT_INFO_ISSUER_NAME:
|
||||
return lws_tls_mbedtls_get_x509_name(&x509->issuer, buf, len);
|
||||
|
||||
case LWS_TLS_CERT_INFO_USAGE:
|
||||
buf->usage = x509->key_usage;
|
||||
break;
|
||||
|
||||
case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY:
|
||||
{
|
||||
char *p = buf->ns.name;
|
||||
size_t r = len, u;
|
||||
|
||||
switch (mbedtls_pk_get_type(&x509->pk)) {
|
||||
case MBEDTLS_PK_RSA:
|
||||
{
|
||||
mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509->pk);
|
||||
|
||||
if (mbedtls_mpi_write_string(&rsa->N, 16, p, r, &u))
|
||||
return -1;
|
||||
r -= u;
|
||||
p += u;
|
||||
if (mbedtls_mpi_write_string(&rsa->E, 16, p, r, &u))
|
||||
return -1;
|
||||
|
||||
p += u;
|
||||
buf->ns.len = lws_ptr_diff(p, buf->ns.name);
|
||||
break;
|
||||
}
|
||||
case MBEDTLS_PK_ECKEY:
|
||||
{
|
||||
mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(x509->pk);
|
||||
|
||||
if (mbedtls_mpi_write_string(&ecp->Q.X, 16, p, r, &u))
|
||||
return -1;
|
||||
r -= u;
|
||||
p += u;
|
||||
if (mbedtls_mpi_write_string(&ecp->Q.Y, 16, p, r, &u))
|
||||
return -1;
|
||||
r -= u;
|
||||
p += u;
|
||||
if (mbedtls_mpi_write_string(&ecp->Q.Z, 16, p, r, &u))
|
||||
return -1;
|
||||
p += u;
|
||||
buf->ns.len = lws_ptr_diff(p, buf->ns.name);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lwsl_notice("%s: x509 has unsupported pubkey type %d\n",
|
||||
__func__,
|
||||
mbedtls_pk_get_type(&x509->pk));
|
||||
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
{
|
||||
mbedtls_x509_crt *x509 = ssl_ctx_get_mbedtls_x509_crt(vhost->tls.ssl_ctx);
|
||||
|
||||
return lws_tls_mbedtls_cert_info(x509, type, buf, len);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
{
|
||||
mbedtls_x509_crt *x509;
|
||||
|
||||
wsi = lws_get_network_wsi(wsi);
|
||||
|
||||
x509 = ssl_get_peer_mbedtls_x509_crt(wsi->tls.ssl);
|
||||
|
||||
if (!x509)
|
||||
return -1;
|
||||
|
||||
switch (type) {
|
||||
case LWS_TLS_CERT_INFO_VERIFIED:
|
||||
buf->verified = SSL_get_verify_result(wsi->tls.ssl) == X509_V_OK;
|
||||
return 0;
|
||||
default:
|
||||
return lws_tls_mbedtls_cert_info(x509, type, buf, len);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
tops_fake_POLLIN_for_buffered_mbedtls(struct lws_context_per_thread *pt)
|
||||
{
|
||||
return lws_tls_fake_POLLIN_for_buffered(pt);
|
||||
}
|
||||
|
||||
static int
|
||||
tops_periodic_housekeeping_mbedtls(struct lws_context *context, time_t now)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = lws_compare_time_t(context, now, context->tls.last_cert_check_s);
|
||||
if ((!context->tls.last_cert_check_s || n > (24 * 60 * 60)) &&
|
||||
!lws_tls_check_all_cert_lifetimes(context))
|
||||
context->tls.last_cert_check_s = now;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct lws_tls_ops tls_ops_mbedtls = {
|
||||
/* fake_POLLIN_for_buffered */ tops_fake_POLLIN_for_buffered_mbedtls,
|
||||
/* periodic_housekeeping */ tops_periodic_housekeeping_mbedtls,
|
||||
};
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL3_H_
|
||||
#define _SSL3_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
# define SSL3_AD_CLOSE_NOTIFY 0
|
||||
# define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */
|
||||
# define SSL3_AD_BAD_RECORD_MAC 20/* fatal */
|
||||
# define SSL3_AD_DECOMPRESSION_FAILURE 30/* fatal */
|
||||
# define SSL3_AD_HANDSHAKE_FAILURE 40/* fatal */
|
||||
# define SSL3_AD_NO_CERTIFICATE 41
|
||||
# define SSL3_AD_BAD_CERTIFICATE 42
|
||||
# define SSL3_AD_UNSUPPORTED_CERTIFICATE 43
|
||||
# define SSL3_AD_CERTIFICATE_REVOKED 44
|
||||
# define SSL3_AD_CERTIFICATE_EXPIRED 45
|
||||
# define SSL3_AD_CERTIFICATE_UNKNOWN 46
|
||||
# define SSL3_AD_ILLEGAL_PARAMETER 47/* fatal */
|
||||
|
||||
# define SSL3_AL_WARNING 1
|
||||
# define SSL3_AL_FATAL 2
|
||||
|
||||
#define SSL3_VERSION 0x0300
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_CERT_H_
|
||||
#define _SSL_CERT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssl_types.h"
|
||||
|
||||
/**
|
||||
* @brief create a certification object include private key object according to input certification
|
||||
*
|
||||
* @param ic - input certification point
|
||||
*
|
||||
* @return certification object point
|
||||
*/
|
||||
CERT *__ssl_cert_new(CERT *ic);
|
||||
|
||||
/**
|
||||
* @brief create a certification object include private key object
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return certification object point
|
||||
*/
|
||||
CERT* ssl_cert_new(void);
|
||||
|
||||
/**
|
||||
* @brief free a certification object
|
||||
*
|
||||
* @param cert - certification object point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void ssl_cert_free(CERT *cert);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,124 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_CODE_H_
|
||||
#define _SSL_CODE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssl3.h"
|
||||
#include "tls1.h"
|
||||
#include "x509_vfy.h"
|
||||
|
||||
/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
|
||||
# define SSL_SENT_SHUTDOWN 1
|
||||
# define SSL_RECEIVED_SHUTDOWN 2
|
||||
|
||||
# define SSL_VERIFY_NONE 0x00
|
||||
# define SSL_VERIFY_PEER 0x01
|
||||
# define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
|
||||
# define SSL_VERIFY_CLIENT_ONCE 0x04
|
||||
|
||||
/*
|
||||
* The following 3 states are kept in ssl->rlayer.rstate when reads fail, you
|
||||
* should not need these
|
||||
*/
|
||||
# define SSL_ST_READ_HEADER 0xF0
|
||||
# define SSL_ST_READ_BODY 0xF1
|
||||
# define SSL_ST_READ_DONE 0xF2
|
||||
|
||||
# define SSL_NOTHING 1
|
||||
# define SSL_WRITING 2
|
||||
# define SSL_READING 3
|
||||
# define SSL_X509_LOOKUP 4
|
||||
# define SSL_ASYNC_PAUSED 5
|
||||
# define SSL_ASYNC_NO_JOBS 6
|
||||
|
||||
|
||||
# define SSL_ERROR_NONE 0
|
||||
# define SSL_ERROR_SSL 1
|
||||
# define SSL_ERROR_WANT_READ 2
|
||||
# define SSL_ERROR_WANT_WRITE 3
|
||||
# define SSL_ERROR_WANT_X509_LOOKUP 4
|
||||
# define SSL_ERROR_SYSCALL 5/* look at error stack/return value/errno */
|
||||
# define SSL_ERROR_ZERO_RETURN 6
|
||||
# define SSL_ERROR_WANT_CONNECT 7
|
||||
# define SSL_ERROR_WANT_ACCEPT 8
|
||||
# define SSL_ERROR_WANT_ASYNC 9
|
||||
# define SSL_ERROR_WANT_ASYNC_JOB 10
|
||||
|
||||
/* Message flow states */
|
||||
typedef enum {
|
||||
/* No handshake in progress */
|
||||
MSG_FLOW_UNINITED,
|
||||
/* A permanent error with this connection */
|
||||
MSG_FLOW_ERROR,
|
||||
/* We are about to renegotiate */
|
||||
MSG_FLOW_RENEGOTIATE,
|
||||
/* We are reading messages */
|
||||
MSG_FLOW_READING,
|
||||
/* We are writing messages */
|
||||
MSG_FLOW_WRITING,
|
||||
/* Handshake has finished */
|
||||
MSG_FLOW_FINISHED
|
||||
} MSG_FLOW_STATE;
|
||||
|
||||
/* SSL subsystem states */
|
||||
typedef enum {
|
||||
TLS_ST_BEFORE,
|
||||
TLS_ST_OK,
|
||||
DTLS_ST_CR_HELLO_VERIFY_REQUEST,
|
||||
TLS_ST_CR_SRVR_HELLO,
|
||||
TLS_ST_CR_CERT,
|
||||
TLS_ST_CR_CERT_STATUS,
|
||||
TLS_ST_CR_KEY_EXCH,
|
||||
TLS_ST_CR_CERT_REQ,
|
||||
TLS_ST_CR_SRVR_DONE,
|
||||
TLS_ST_CR_SESSION_TICKET,
|
||||
TLS_ST_CR_CHANGE,
|
||||
TLS_ST_CR_FINISHED,
|
||||
TLS_ST_CW_CLNT_HELLO,
|
||||
TLS_ST_CW_CERT,
|
||||
TLS_ST_CW_KEY_EXCH,
|
||||
TLS_ST_CW_CERT_VRFY,
|
||||
TLS_ST_CW_CHANGE,
|
||||
TLS_ST_CW_NEXT_PROTO,
|
||||
TLS_ST_CW_FINISHED,
|
||||
TLS_ST_SW_HELLO_REQ,
|
||||
TLS_ST_SR_CLNT_HELLO,
|
||||
DTLS_ST_SW_HELLO_VERIFY_REQUEST,
|
||||
TLS_ST_SW_SRVR_HELLO,
|
||||
TLS_ST_SW_CERT,
|
||||
TLS_ST_SW_KEY_EXCH,
|
||||
TLS_ST_SW_CERT_REQ,
|
||||
TLS_ST_SW_SRVR_DONE,
|
||||
TLS_ST_SR_CERT,
|
||||
TLS_ST_SR_KEY_EXCH,
|
||||
TLS_ST_SR_CERT_VRFY,
|
||||
TLS_ST_SR_NEXT_PROTO,
|
||||
TLS_ST_SR_CHANGE,
|
||||
TLS_ST_SR_FINISHED,
|
||||
TLS_ST_SW_SESSION_TICKET,
|
||||
TLS_ST_SW_CERT_STATUS,
|
||||
TLS_ST_SW_CHANGE,
|
||||
TLS_ST_SW_FINISHED
|
||||
} OSSL_HANDSHAKE_STATE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,190 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_DEBUG_H_
|
||||
#define _SSL_DEBUG_H_
|
||||
|
||||
#include "platform/ssl_port.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OPENSSL_DEBUG_LEVEL
|
||||
#define SSL_DEBUG_LEVEL CONFIG_OPENSSL_DEBUG_LEVEL
|
||||
#else
|
||||
#define SSL_DEBUG_LEVEL 0
|
||||
#endif
|
||||
|
||||
#define SSL_DEBUG_ON (SSL_DEBUG_LEVEL + 1)
|
||||
#define SSL_DEBUG_OFF (SSL_DEBUG_LEVEL - 1)
|
||||
|
||||
#ifdef CONFIG_OPENSSL_DEBUG
|
||||
#ifndef SSL_DEBUG_LOG
|
||||
#error "SSL_DEBUG_LOG is not defined"
|
||||
#endif
|
||||
|
||||
#ifndef SSL_DEBUG_FL
|
||||
#define SSL_DEBUG_FL "\n"
|
||||
#endif
|
||||
|
||||
#define SSL_SHOW_LOCATION() \
|
||||
SSL_DEBUG_LOG("SSL assert : %s %d\n", \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
#define SSL_DEBUG(level, fmt, ...) \
|
||||
{ \
|
||||
if (level > SSL_DEBUG_LEVEL) { \
|
||||
SSL_DEBUG_LOG(fmt SSL_DEBUG_FL, ##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#else /* CONFIG_OPENSSL_DEBUG */
|
||||
#define SSL_SHOW_LOCATION()
|
||||
|
||||
#define SSL_DEBUG(level, fmt, ...)
|
||||
#endif /* CONFIG_OPENSSL_DEBUG */
|
||||
|
||||
/**
|
||||
* OpenSSL assert function
|
||||
*
|
||||
* if select "CONFIG_OPENSSL_ASSERT_DEBUG", SSL_ASSERT* will show error file name and line
|
||||
* if select "CONFIG_OPENSSL_ASSERT_EXIT", SSL_ASSERT* will just return error code.
|
||||
* if select "CONFIG_OPENSSL_ASSERT_DEBUG_EXIT" SSL_ASSERT* will show error file name and line,
|
||||
* then return error code.
|
||||
* if select "CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK", SSL_ASSERT* will show error file name and line,
|
||||
* then block here with "while (1)"
|
||||
*
|
||||
* SSL_ASSERT1 may will return "-1", so function's return argument is integer.
|
||||
* SSL_ASSERT2 may will return "NULL", so function's return argument is a point.
|
||||
* SSL_ASSERT2 may will return nothing, so function's return argument is "void".
|
||||
*/
|
||||
#if defined(CONFIG_OPENSSL_ASSERT_DEBUG)
|
||||
#define SSL_ASSERT1(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT2(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT3(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
} \
|
||||
}
|
||||
#elif defined(CONFIG_OPENSSL_ASSERT_EXIT)
|
||||
#define SSL_ASSERT1(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT2(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
return NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT3(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
return ; \
|
||||
} \
|
||||
}
|
||||
#elif defined(CONFIG_OPENSSL_ASSERT_DEBUG_EXIT)
|
||||
#define SSL_ASSERT1(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT2(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
return NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT3(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
return ; \
|
||||
} \
|
||||
}
|
||||
#elif defined(CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK)
|
||||
#define SSL_ASSERT1(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
while (1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT2(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
while (1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SSL_ASSERT3(s) \
|
||||
{ \
|
||||
if (!(s)) { \
|
||||
SSL_SHOW_LOCATION(); \
|
||||
while (1); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define SSL_ASSERT1(s)
|
||||
#define SSL_ASSERT2(s)
|
||||
#define SSL_ASSERT3(s)
|
||||
#endif
|
||||
|
||||
#define SSL_PLATFORM_DEBUG_LEVEL SSL_DEBUG_OFF
|
||||
#define SSL_PLATFORM_ERROR_LEVEL SSL_DEBUG_ON
|
||||
|
||||
#define SSL_CERT_DEBUG_LEVEL SSL_DEBUG_OFF
|
||||
#define SSL_CERT_ERROR_LEVEL SSL_DEBUG_ON
|
||||
|
||||
#define SSL_PKEY_DEBUG_LEVEL SSL_DEBUG_OFF
|
||||
#define SSL_PKEY_ERROR_LEVEL SSL_DEBUG_ON
|
||||
|
||||
#define SSL_X509_DEBUG_LEVEL SSL_DEBUG_OFF
|
||||
#define SSL_X509_ERROR_LEVEL SSL_DEBUG_ON
|
||||
|
||||
#define SSL_LIB_DEBUG_LEVEL SSL_DEBUG_OFF
|
||||
#define SSL_LIB_ERROR_LEVEL SSL_DEBUG_ON
|
||||
|
||||
#define SSL_STACK_DEBUG_LEVEL SSL_DEBUG_OFF
|
||||
#define SSL_STACK_ERROR_LEVEL SSL_DEBUG_ON
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_LIB_H_
|
||||
#define _SSL_LIB_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssl_types.h"
|
||||
|
||||
void _ssl_set_alpn_list(const SSL *ssl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,121 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_METHODS_H_
|
||||
#define _SSL_METHODS_H_
|
||||
|
||||
#include "ssl_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TLS method function implement
|
||||
*/
|
||||
#define IMPLEMENT_TLS_METHOD_FUNC(func_name, \
|
||||
new, free, \
|
||||
handshake, shutdown, clear, \
|
||||
read, send, pending, \
|
||||
set_fd, get_fd, \
|
||||
set_bufflen, \
|
||||
get_verify_result, \
|
||||
get_state) \
|
||||
static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \
|
||||
new, \
|
||||
free, \
|
||||
handshake, \
|
||||
shutdown, \
|
||||
clear, \
|
||||
read, \
|
||||
send, \
|
||||
pending, \
|
||||
set_fd, \
|
||||
get_fd, \
|
||||
set_bufflen, \
|
||||
get_verify_result, \
|
||||
get_state \
|
||||
};
|
||||
|
||||
#define IMPLEMENT_TLS_METHOD(ver, mode, fun, func_name) \
|
||||
const SSL_METHOD* func_name(void) { \
|
||||
static const SSL_METHOD func_name##_data LOCAL_ATRR = { \
|
||||
ver, \
|
||||
mode, \
|
||||
&(fun), \
|
||||
}; \
|
||||
return &func_name##_data; \
|
||||
}
|
||||
|
||||
#define IMPLEMENT_SSL_METHOD(ver, mode, fun, func_name) \
|
||||
const SSL_METHOD* func_name(void) { \
|
||||
static const SSL_METHOD func_name##_data LOCAL_ATRR = { \
|
||||
ver, \
|
||||
mode, \
|
||||
&(fun), \
|
||||
}; \
|
||||
return &func_name##_data; \
|
||||
}
|
||||
|
||||
#define IMPLEMENT_X509_METHOD(func_name, \
|
||||
new, \
|
||||
free, \
|
||||
load, \
|
||||
show_info) \
|
||||
const X509_METHOD* func_name(void) { \
|
||||
static const X509_METHOD func_name##_data LOCAL_ATRR = { \
|
||||
new, \
|
||||
free, \
|
||||
load, \
|
||||
show_info \
|
||||
}; \
|
||||
return &func_name##_data; \
|
||||
}
|
||||
|
||||
#define IMPLEMENT_PKEY_METHOD(func_name, \
|
||||
new, \
|
||||
free, \
|
||||
load) \
|
||||
const PKEY_METHOD* func_name(void) { \
|
||||
static const PKEY_METHOD func_name##_data LOCAL_ATRR = { \
|
||||
new, \
|
||||
free, \
|
||||
load \
|
||||
}; \
|
||||
return &func_name##_data; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get X509 object method
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return X509 object method point
|
||||
*/
|
||||
const X509_METHOD* X509_method(void);
|
||||
|
||||
/**
|
||||
* @brief get private key object method
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return private key object method point
|
||||
*/
|
||||
const PKEY_METHOD* EVP_PKEY_method(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,86 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_PKEY_H_
|
||||
#define _SSL_PKEY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssl_types.h"
|
||||
|
||||
/**
|
||||
* @brief create a private key object according to input private key
|
||||
*
|
||||
* @param ipk - input private key point
|
||||
*
|
||||
* @return new private key object point
|
||||
*/
|
||||
EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk);
|
||||
|
||||
/**
|
||||
* @brief create a private key object
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return private key object point
|
||||
*/
|
||||
EVP_PKEY* EVP_PKEY_new(void);
|
||||
|
||||
/**
|
||||
* @brief load a character key context into system context. If '*a' is pointed to the
|
||||
* private key, then load key into it. Or create a new private key object
|
||||
*
|
||||
* @param type - private key type
|
||||
* @param a - a point pointed to a private key point
|
||||
* @param pp - a point pointed to the key context memory point
|
||||
* @param length - key bytes
|
||||
*
|
||||
* @return private key object point
|
||||
*/
|
||||
EVP_PKEY* d2i_PrivateKey(int type,
|
||||
EVP_PKEY **a,
|
||||
const unsigned char **pp,
|
||||
long length);
|
||||
|
||||
/**
|
||||
* @brief free a private key object
|
||||
*
|
||||
* @param pkey - private key object point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void EVP_PKEY_free(EVP_PKEY *x);
|
||||
|
||||
/**
|
||||
* @brief load private key into the SSL
|
||||
*
|
||||
* @param type - private key type
|
||||
* @param ssl - SSL point
|
||||
* @param len - data bytes
|
||||
* @param d - data point
|
||||
*
|
||||
* @return result
|
||||
* 0 : failed
|
||||
* 1 : OK
|
||||
*/
|
||||
int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef _SSL_STACK_H_
|
||||
#define _SSL_STACK_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssl_types.h"
|
||||
|
||||
#define STACK_OF(type) struct stack_st_##type
|
||||
|
||||
#define SKM_DEFINE_STACK_OF(t1, t2, t3) \
|
||||
STACK_OF(t1); \
|
||||
static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \
|
||||
{ \
|
||||
return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \
|
||||
} \
|
||||
|
||||
#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t)
|
||||
|
||||
/**
|
||||
* @brief create a openssl stack object
|
||||
*
|
||||
* @param c - stack function
|
||||
*
|
||||
* @return openssl stack object point
|
||||
*/
|
||||
OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c);
|
||||
|
||||
/**
|
||||
* @brief create a NULL function openssl stack object
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return openssl stack object point
|
||||
*/
|
||||
OPENSSL_STACK *OPENSSL_sk_new_null(void);
|
||||
|
||||
/**
|
||||
* @brief free openssl stack object
|
||||
*
|
||||
* @param openssl stack object point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void OPENSSL_sk_free(OPENSSL_STACK *stack);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,303 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_TYPES_H_
|
||||
#define _SSL_TYPES_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <lws_config.h>
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
#undef MBEDTLS_CONFIG_FILE
|
||||
#define MBEDTLS_CONFIG_FILE <mbedtls/esp_config.h>
|
||||
#endif
|
||||
|
||||
#include "ssl_code.h"
|
||||
|
||||
typedef void SSL_CIPHER;
|
||||
|
||||
typedef void X509_STORE_CTX;
|
||||
typedef void X509_STORE;
|
||||
|
||||
typedef void RSA;
|
||||
|
||||
typedef void STACK;
|
||||
typedef void BIO;
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define ossl_inline __inline
|
||||
#else
|
||||
#define ossl_inline inline
|
||||
#endif
|
||||
|
||||
#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__)
|
||||
#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__)
|
||||
#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__)
|
||||
|
||||
typedef int (*OPENSSL_sk_compfunc)(const void *, const void *);
|
||||
|
||||
struct stack_st;
|
||||
typedef struct stack_st OPENSSL_STACK;
|
||||
|
||||
struct ssl_method_st;
|
||||
typedef struct ssl_method_st SSL_METHOD;
|
||||
|
||||
struct ssl_method_func_st;
|
||||
typedef struct ssl_method_func_st SSL_METHOD_FUNC;
|
||||
|
||||
struct record_layer_st;
|
||||
typedef struct record_layer_st RECORD_LAYER;
|
||||
|
||||
struct ossl_statem_st;
|
||||
typedef struct ossl_statem_st OSSL_STATEM;
|
||||
|
||||
struct ssl_session_st;
|
||||
typedef struct ssl_session_st SSL_SESSION;
|
||||
|
||||
struct ssl_ctx_st;
|
||||
typedef struct ssl_ctx_st SSL_CTX;
|
||||
|
||||
struct ssl_st;
|
||||
typedef struct ssl_st SSL;
|
||||
|
||||
struct cert_st;
|
||||
typedef struct cert_st CERT;
|
||||
|
||||
struct x509_st;
|
||||
typedef struct x509_st X509;
|
||||
|
||||
struct X509_VERIFY_PARAM_st;
|
||||
typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM;
|
||||
|
||||
struct evp_pkey_st;
|
||||
typedef struct evp_pkey_st EVP_PKEY;
|
||||
|
||||
struct x509_method_st;
|
||||
typedef struct x509_method_st X509_METHOD;
|
||||
|
||||
struct pkey_method_st;
|
||||
typedef struct pkey_method_st PKEY_METHOD;
|
||||
|
||||
struct stack_st {
|
||||
|
||||
char **data;
|
||||
|
||||
int num_alloc;
|
||||
|
||||
OPENSSL_sk_compfunc c;
|
||||
};
|
||||
|
||||
struct evp_pkey_st {
|
||||
|
||||
void *pkey_pm;
|
||||
|
||||
const PKEY_METHOD *method;
|
||||
};
|
||||
|
||||
struct x509_st {
|
||||
|
||||
/* X509 certification platform private point */
|
||||
void *x509_pm;
|
||||
|
||||
const X509_METHOD *method;
|
||||
};
|
||||
|
||||
struct cert_st {
|
||||
|
||||
int sec_level;
|
||||
|
||||
X509 *x509;
|
||||
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
};
|
||||
|
||||
struct ossl_statem_st {
|
||||
|
||||
MSG_FLOW_STATE state;
|
||||
|
||||
int hand_state;
|
||||
};
|
||||
|
||||
struct record_layer_st {
|
||||
|
||||
int rstate;
|
||||
|
||||
int read_ahead;
|
||||
};
|
||||
|
||||
struct ssl_session_st {
|
||||
|
||||
long timeout;
|
||||
|
||||
long time;
|
||||
|
||||
X509 *peer;
|
||||
};
|
||||
|
||||
struct X509_VERIFY_PARAM_st {
|
||||
|
||||
int depth;
|
||||
|
||||
};
|
||||
|
||||
typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg);
|
||||
|
||||
struct ssl_ctx_st
|
||||
{
|
||||
int version;
|
||||
|
||||
int references;
|
||||
|
||||
unsigned long options;
|
||||
|
||||
const SSL_METHOD *method;
|
||||
|
||||
CERT *cert;
|
||||
|
||||
X509 *client_CA;
|
||||
|
||||
const char **alpn_protos;
|
||||
|
||||
next_proto_cb alpn_cb;
|
||||
|
||||
int verify_mode;
|
||||
|
||||
int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx);
|
||||
|
||||
long session_timeout;
|
||||
|
||||
int read_ahead;
|
||||
|
||||
int read_buffer_len;
|
||||
|
||||
X509_VERIFY_PARAM param;
|
||||
};
|
||||
|
||||
struct ssl_st
|
||||
{
|
||||
/* protocol version(one of SSL3.0, TLS1.0, etc.) */
|
||||
int version;
|
||||
|
||||
unsigned long options;
|
||||
|
||||
/* shut things down(0x01 : sent, 0x02 : received) */
|
||||
int shutdown;
|
||||
|
||||
CERT *cert;
|
||||
|
||||
X509 *client_CA;
|
||||
|
||||
SSL_CTX *ctx;
|
||||
|
||||
const SSL_METHOD *method;
|
||||
|
||||
const char **alpn_protos;
|
||||
|
||||
RECORD_LAYER rlayer;
|
||||
|
||||
/* where we are */
|
||||
OSSL_STATEM statem;
|
||||
|
||||
SSL_SESSION *session;
|
||||
|
||||
int verify_mode;
|
||||
|
||||
int (*verify_callback) (int ok, X509_STORE_CTX *ctx);
|
||||
|
||||
int rwstate;
|
||||
int interrupted_remaining_write;
|
||||
|
||||
long verify_result;
|
||||
|
||||
X509_VERIFY_PARAM param;
|
||||
|
||||
int err;
|
||||
|
||||
void (*info_callback) (const SSL *ssl, int type, int val);
|
||||
|
||||
/* SSL low-level system arch point */
|
||||
void *ssl_pm;
|
||||
};
|
||||
|
||||
struct ssl_method_st {
|
||||
/* protocol version(one of SSL3.0, TLS1.0, etc.) */
|
||||
int version;
|
||||
|
||||
/* SSL mode(client(0) , server(1), not known(-1)) */
|
||||
int endpoint;
|
||||
|
||||
const SSL_METHOD_FUNC *func;
|
||||
};
|
||||
|
||||
struct ssl_method_func_st {
|
||||
|
||||
int (*ssl_new)(SSL *ssl);
|
||||
|
||||
void (*ssl_free)(SSL *ssl);
|
||||
|
||||
int (*ssl_handshake)(SSL *ssl);
|
||||
|
||||
int (*ssl_shutdown)(SSL *ssl);
|
||||
|
||||
int (*ssl_clear)(SSL *ssl);
|
||||
|
||||
int (*ssl_read)(SSL *ssl, void *buffer, int len);
|
||||
|
||||
int (*ssl_send)(SSL *ssl, const void *buffer, int len);
|
||||
|
||||
int (*ssl_pending)(const SSL *ssl);
|
||||
|
||||
void (*ssl_set_fd)(SSL *ssl, int fd, int mode);
|
||||
|
||||
int (*ssl_get_fd)(const SSL *ssl, int mode);
|
||||
|
||||
void (*ssl_set_bufflen)(SSL *ssl, int len);
|
||||
|
||||
long (*ssl_get_verify_result)(const SSL *ssl);
|
||||
|
||||
OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl);
|
||||
};
|
||||
|
||||
struct x509_method_st {
|
||||
|
||||
int (*x509_new)(X509 *x, X509 *m_x);
|
||||
|
||||
void (*x509_free)(X509 *x);
|
||||
|
||||
int (*x509_load)(X509 *x, const unsigned char *buf, int len);
|
||||
|
||||
int (*x509_show_info)(X509 *x);
|
||||
};
|
||||
|
||||
struct pkey_method_st {
|
||||
|
||||
int (*pkey_new)(EVP_PKEY *pkey, EVP_PKEY *m_pkey);
|
||||
|
||||
void (*pkey_free)(EVP_PKEY *pkey);
|
||||
|
||||
int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len);
|
||||
};
|
||||
|
||||
#define OPENSSL_NPN_NEGOTIATED 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,110 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_X509_H_
|
||||
#define _SSL_X509_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssl_types.h"
|
||||
#include "ssl_stack.h"
|
||||
|
||||
DEFINE_STACK_OF(X509_NAME)
|
||||
|
||||
/**
|
||||
* @brief create a X509 certification object according to input X509 certification
|
||||
*
|
||||
* @param ix - input X509 certification point
|
||||
*
|
||||
* @return new X509 certification object point
|
||||
*/
|
||||
X509* __X509_new(X509 *ix);
|
||||
|
||||
/**
|
||||
* @brief create a X509 certification object
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return X509 certification object point
|
||||
*/
|
||||
X509* X509_new(void);
|
||||
|
||||
/**
|
||||
* @brief load a character certification context into system context. If '*cert' is pointed to the
|
||||
* certification, then load certification into it. Or create a new X509 certification object
|
||||
*
|
||||
* @param cert - a point pointed to X509 certification
|
||||
* @param buffer - a point pointed to the certification context memory point
|
||||
* @param length - certification bytes
|
||||
*
|
||||
* @return X509 certification object point
|
||||
*/
|
||||
X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len);
|
||||
|
||||
/**
|
||||
* @brief free a X509 certification object
|
||||
*
|
||||
* @param x - X509 certification object point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void X509_free(X509 *x);
|
||||
|
||||
/**
|
||||
* @brief set SSL context client CA certification
|
||||
*
|
||||
* @param ctx - SSL context point
|
||||
* @param x - X509 certification point
|
||||
*
|
||||
* @return result
|
||||
* 0 : failed
|
||||
* 1 : OK
|
||||
*/
|
||||
int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x);
|
||||
|
||||
/**
|
||||
* @brief add CA client certification into the SSL
|
||||
*
|
||||
* @param ssl - SSL point
|
||||
* @param x - X509 certification point
|
||||
*
|
||||
* @return result
|
||||
* 0 : failed
|
||||
* 1 : OK
|
||||
*/
|
||||
int SSL_add_client_CA(SSL *ssl, X509 *x);
|
||||
|
||||
/**
|
||||
* @brief load certification into the SSL
|
||||
*
|
||||
* @param ssl - SSL point
|
||||
* @param len - data bytes
|
||||
* @param d - data point
|
||||
*
|
||||
* @return result
|
||||
* 0 : failed
|
||||
* 1 : OK
|
||||
*
|
||||
*/
|
||||
int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d);
|
||||
|
||||
const char *X509_verify_cert_error_string(long n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _TLS1_H_
|
||||
#define _TLS1_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
# define TLS1_AD_DECRYPTION_FAILED 21
|
||||
# define TLS1_AD_RECORD_OVERFLOW 22
|
||||
# define TLS1_AD_UNKNOWN_CA 48/* fatal */
|
||||
# define TLS1_AD_ACCESS_DENIED 49/* fatal */
|
||||
# define TLS1_AD_DECODE_ERROR 50/* fatal */
|
||||
# define TLS1_AD_DECRYPT_ERROR 51
|
||||
# define TLS1_AD_EXPORT_RESTRICTION 60/* fatal */
|
||||
# define TLS1_AD_PROTOCOL_VERSION 70/* fatal */
|
||||
# define TLS1_AD_INSUFFICIENT_SECURITY 71/* fatal */
|
||||
# define TLS1_AD_INTERNAL_ERROR 80/* fatal */
|
||||
# define TLS1_AD_INAPPROPRIATE_FALLBACK 86/* fatal */
|
||||
# define TLS1_AD_USER_CANCELLED 90
|
||||
# define TLS1_AD_NO_RENEGOTIATION 100
|
||||
/* codes 110-114 are from RFC3546 */
|
||||
# define TLS1_AD_UNSUPPORTED_EXTENSION 110
|
||||
# define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111
|
||||
# define TLS1_AD_UNRECOGNIZED_NAME 112
|
||||
# define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113
|
||||
# define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
|
||||
# define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */
|
||||
# define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */
|
||||
|
||||
/* Special value for method supporting multiple versions */
|
||||
#define TLS_ANY_VERSION 0x10000
|
||||
|
||||
#define TLS1_VERSION 0x0301
|
||||
#define TLS1_1_VERSION 0x0302
|
||||
#define TLS1_2_VERSION 0x0303
|
||||
|
||||
#define SSL_TLSEXT_ERR_OK 0
|
||||
#define SSL_TLSEXT_ERR_NOACK 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,116 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _X509_VFY_H_
|
||||
#define _X509_VFY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define X509_V_OK 0
|
||||
#define X509_V_ERR_UNSPECIFIED 1
|
||||
#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2
|
||||
#define X509_V_ERR_UNABLE_TO_GET_CRL 3
|
||||
#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4
|
||||
#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5
|
||||
#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6
|
||||
#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
|
||||
#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8
|
||||
#define X509_V_ERR_CERT_NOT_YET_VALID 9
|
||||
#define X509_V_ERR_CERT_HAS_EXPIRED 10
|
||||
#define X509_V_ERR_CRL_NOT_YET_VALID 11
|
||||
#define X509_V_ERR_CRL_HAS_EXPIRED 12
|
||||
#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13
|
||||
#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14
|
||||
#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15
|
||||
#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16
|
||||
#define X509_V_ERR_OUT_OF_MEM 17
|
||||
#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18
|
||||
#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19
|
||||
#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20
|
||||
#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21
|
||||
#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22
|
||||
#define X509_V_ERR_CERT_REVOKED 23
|
||||
#define X509_V_ERR_INVALID_CA 24
|
||||
#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
|
||||
#define X509_V_ERR_INVALID_PURPOSE 26
|
||||
#define X509_V_ERR_CERT_UNTRUSTED 27
|
||||
#define X509_V_ERR_CERT_REJECTED 28
|
||||
/* These are 'informational' when looking for issuer cert */
|
||||
#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29
|
||||
#define X509_V_ERR_AKID_SKID_MISMATCH 30
|
||||
#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
|
||||
#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
|
||||
#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
|
||||
#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
|
||||
#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35
|
||||
#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36
|
||||
#define X509_V_ERR_INVALID_NON_CA 37
|
||||
#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
|
||||
#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39
|
||||
#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40
|
||||
#define X509_V_ERR_INVALID_EXTENSION 41
|
||||
#define X509_V_ERR_INVALID_POLICY_EXTENSION 42
|
||||
#define X509_V_ERR_NO_EXPLICIT_POLICY 43
|
||||
#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44
|
||||
#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45
|
||||
#define X509_V_ERR_UNNESTED_RESOURCE 46
|
||||
#define X509_V_ERR_PERMITTED_VIOLATION 47
|
||||
#define X509_V_ERR_EXCLUDED_VIOLATION 48
|
||||
#define X509_V_ERR_SUBTREE_MINMAX 49
|
||||
/* The application is not happy */
|
||||
#define X509_V_ERR_APPLICATION_VERIFICATION 50
|
||||
#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51
|
||||
#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52
|
||||
#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53
|
||||
#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54
|
||||
/* Another issuer check debug option */
|
||||
#define X509_V_ERR_PATH_LOOP 55
|
||||
/* Suite B mode algorithm violation */
|
||||
#define X509_V_ERR_SUITE_B_INVALID_VERSION 56
|
||||
#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57
|
||||
#define X509_V_ERR_SUITE_B_INVALID_CURVE 58
|
||||
#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59
|
||||
#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60
|
||||
#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61
|
||||
/* Host, email and IP check errors */
|
||||
#define X509_V_ERR_HOSTNAME_MISMATCH 62
|
||||
#define X509_V_ERR_EMAIL_MISMATCH 63
|
||||
#define X509_V_ERR_IP_ADDRESS_MISMATCH 64
|
||||
/* DANE TLSA errors */
|
||||
#define X509_V_ERR_DANE_NO_MATCH 65
|
||||
/* security level errors */
|
||||
#define X509_V_ERR_EE_KEY_TOO_SMALL 66
|
||||
#define X509_V_ERR_CA_KEY_TOO_SMALL 67
|
||||
#define X509_V_ERR_CA_MD_TOO_WEAK 68
|
||||
/* Caller error */
|
||||
#define X509_V_ERR_INVALID_CALL 69
|
||||
/* Issuer lookup error */
|
||||
#define X509_V_ERR_STORE_LOOKUP 70
|
||||
/* Certificate transparency */
|
||||
#define X509_V_ERR_NO_VALID_SCTS 71
|
||||
|
||||
#define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72
|
||||
|
||||
typedef void X509_STORE_CTX;
|
||||
int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
|
||||
int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,61 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_PM_H_
|
||||
#define _SSL_PM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "ssl_types.h"
|
||||
#include "ssl_port.h"
|
||||
|
||||
#define LOCAL_ATRR
|
||||
|
||||
int ssl_pm_new(SSL *ssl);
|
||||
void ssl_pm_free(SSL *ssl);
|
||||
|
||||
int ssl_pm_handshake(SSL *ssl);
|
||||
int ssl_pm_shutdown(SSL *ssl);
|
||||
int ssl_pm_clear(SSL *ssl);
|
||||
|
||||
int ssl_pm_read(SSL *ssl, void *buffer, int len);
|
||||
int ssl_pm_send(SSL *ssl, const void *buffer, int len);
|
||||
int ssl_pm_pending(const SSL *ssl);
|
||||
|
||||
void ssl_pm_set_fd(SSL *ssl, int fd, int mode);
|
||||
int ssl_pm_get_fd(const SSL *ssl, int mode);
|
||||
|
||||
OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl);
|
||||
|
||||
void ssl_pm_set_bufflen(SSL *ssl, int len);
|
||||
|
||||
int x509_pm_show_info(X509 *x);
|
||||
int x509_pm_new(X509 *x, X509 *m_x);
|
||||
void x509_pm_free(X509 *x);
|
||||
int x509_pm_load(X509 *x, const unsigned char *buffer, int len);
|
||||
|
||||
int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pk);
|
||||
void pkey_pm_free(EVP_PKEY *pk);
|
||||
int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len);
|
||||
|
||||
long ssl_pm_get_verify_result(const SSL *ssl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SSL_PORT_H_
|
||||
#define _SSL_PORT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "string.h"
|
||||
#include "stdlib.h"
|
||||
#if defined(LWS_HAVE_MALLOC_H)
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
|
||||
void *ssl_mem_zalloc(size_t size);
|
||||
|
||||
#define ssl_mem_malloc malloc
|
||||
#define ssl_mem_free free
|
||||
|
||||
#define ssl_memcpy memcpy
|
||||
#define ssl_strlen strlen
|
||||
|
||||
#define ssl_speed_up_enter()
|
||||
#define ssl_speed_up_exit()
|
||||
|
||||
#define SSL_DEBUG_FL
|
||||
#define SSL_DEBUG_LOG(fmt, ...) ESP_LOGI("openssl", fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_cert.h"
|
||||
#include "ssl_pkey.h"
|
||||
#include "ssl_x509.h"
|
||||
#include "ssl_dbg.h"
|
||||
#include "ssl_port.h"
|
||||
|
||||
/**
|
||||
* @brief create a certification object according to input certification
|
||||
*/
|
||||
CERT *__ssl_cert_new(CERT *ic)
|
||||
{
|
||||
CERT *cert;
|
||||
|
||||
X509 *ix;
|
||||
EVP_PKEY *ipk;
|
||||
|
||||
cert = ssl_mem_zalloc(sizeof(CERT));
|
||||
if (!cert) {
|
||||
SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "no enough memory > (cert)");
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (ic) {
|
||||
ipk = ic->pkey;
|
||||
ix = ic->x509;
|
||||
} else {
|
||||
ipk = NULL;
|
||||
ix = NULL;
|
||||
}
|
||||
|
||||
cert->pkey = __EVP_PKEY_new(ipk);
|
||||
if (!cert->pkey) {
|
||||
SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__EVP_PKEY_new() return NULL");
|
||||
goto pkey_err;
|
||||
}
|
||||
|
||||
cert->x509 = __X509_new(ix);
|
||||
if (!cert->x509) {
|
||||
SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__X509_new() return NULL");
|
||||
goto x509_err;
|
||||
}
|
||||
|
||||
return cert;
|
||||
|
||||
x509_err:
|
||||
EVP_PKEY_free(cert->pkey);
|
||||
pkey_err:
|
||||
ssl_mem_free(cert);
|
||||
no_mem:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create a certification object include private key object
|
||||
*/
|
||||
CERT *ssl_cert_new(void)
|
||||
{
|
||||
return __ssl_cert_new(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free a certification object
|
||||
*/
|
||||
void ssl_cert_free(CERT *cert)
|
||||
{
|
||||
SSL_ASSERT3(cert);
|
||||
|
||||
X509_free(cert->x509);
|
||||
|
||||
EVP_PKEY_free(cert->pkey);
|
||||
|
||||
ssl_mem_free(cert);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,81 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_methods.h"
|
||||
#include "ssl_pm.h"
|
||||
|
||||
/**
|
||||
* TLS method function collection
|
||||
*/
|
||||
IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func,
|
||||
ssl_pm_new, ssl_pm_free,
|
||||
ssl_pm_handshake, ssl_pm_shutdown, ssl_pm_clear,
|
||||
ssl_pm_read, ssl_pm_send, ssl_pm_pending,
|
||||
ssl_pm_set_fd, ssl_pm_get_fd,
|
||||
ssl_pm_set_bufflen,
|
||||
ssl_pm_get_verify_result,
|
||||
ssl_pm_get_state);
|
||||
|
||||
/**
|
||||
* TLS or SSL client method collection
|
||||
*/
|
||||
IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method);
|
||||
|
||||
IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 0, TLS_method_func, TLSv1_2_client_method);
|
||||
|
||||
IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 0, TLS_method_func, TLSv1_1_client_method);
|
||||
|
||||
IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method);
|
||||
|
||||
IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method);
|
||||
|
||||
/**
|
||||
* TLS or SSL server method collection
|
||||
*/
|
||||
IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method);
|
||||
|
||||
IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method);
|
||||
|
||||
IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 1, TLS_method_func, TLSv1_2_server_method);
|
||||
|
||||
IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method);
|
||||
|
||||
IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method);
|
||||
|
||||
/**
|
||||
* TLS or SSL method collection
|
||||
*/
|
||||
IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method);
|
||||
|
||||
IMPLEMENT_SSL_METHOD(TLS1_2_VERSION, -1, TLS_method_func, TLSv1_2_method);
|
||||
|
||||
IMPLEMENT_SSL_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method);
|
||||
|
||||
IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method);
|
||||
|
||||
IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method);
|
||||
|
||||
/**
|
||||
* @brief get X509 object method
|
||||
*/
|
||||
IMPLEMENT_X509_METHOD(X509_method,
|
||||
x509_pm_new, x509_pm_free,
|
||||
x509_pm_load, x509_pm_show_info);
|
||||
|
||||
/**
|
||||
* @brief get private key object method
|
||||
*/
|
||||
IMPLEMENT_PKEY_METHOD(EVP_PKEY_method,
|
||||
pkey_pm_new, pkey_pm_free,
|
||||
pkey_pm_load);
|
|
@ -1,239 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_pkey.h"
|
||||
#include "ssl_methods.h"
|
||||
#include "ssl_dbg.h"
|
||||
#include "ssl_port.h"
|
||||
|
||||
/**
|
||||
* @brief create a private key object according to input private key
|
||||
*/
|
||||
EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk)
|
||||
{
|
||||
int ret;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
pkey = ssl_mem_zalloc(sizeof(EVP_PKEY));
|
||||
if (!pkey) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "no enough memory > (pkey)");
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (ipk) {
|
||||
pkey->method = ipk->method;
|
||||
} else {
|
||||
pkey->method = EVP_PKEY_method();
|
||||
}
|
||||
|
||||
ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(new) return %d", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return pkey;
|
||||
|
||||
failed:
|
||||
ssl_mem_free(pkey);
|
||||
no_mem:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create a private key object
|
||||
*/
|
||||
EVP_PKEY* EVP_PKEY_new(void)
|
||||
{
|
||||
return __EVP_PKEY_new(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free a private key object
|
||||
*/
|
||||
void EVP_PKEY_free(EVP_PKEY *pkey)
|
||||
{
|
||||
SSL_ASSERT3(pkey);
|
||||
|
||||
EVP_PKEY_METHOD_CALL(free, pkey);
|
||||
|
||||
ssl_mem_free(pkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load a character key context into system context. If '*a' is pointed to the
|
||||
* private key, then load key into it. Or create a new private key object
|
||||
*/
|
||||
EVP_PKEY *d2i_PrivateKey(int type,
|
||||
EVP_PKEY **a,
|
||||
const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
int m = 0;
|
||||
int ret;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
SSL_ASSERT2(pp);
|
||||
SSL_ASSERT2(*pp);
|
||||
SSL_ASSERT2(length);
|
||||
|
||||
if (a && *a) {
|
||||
pkey = *a;
|
||||
} else {
|
||||
pkey = EVP_PKEY_new();;
|
||||
if (!pkey) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_new() return NULL");
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
m = 1;
|
||||
}
|
||||
|
||||
ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(load) return %d", ret);
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
if (a)
|
||||
*a = pkey;
|
||||
|
||||
return pkey;
|
||||
|
||||
failed2:
|
||||
if (m)
|
||||
EVP_PKEY_free(pkey);
|
||||
failed1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set the SSL context private key
|
||||
*/
|
||||
int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
|
||||
{
|
||||
SSL_ASSERT1(ctx);
|
||||
SSL_ASSERT1(pkey);
|
||||
|
||||
if (ctx->cert->pkey == pkey)
|
||||
return 1;
|
||||
|
||||
if (ctx->cert->pkey)
|
||||
EVP_PKEY_free(ctx->cert->pkey);
|
||||
|
||||
ctx->cert->pkey = pkey;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set the SSL private key
|
||||
*/
|
||||
int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey)
|
||||
{
|
||||
SSL_ASSERT1(ssl);
|
||||
SSL_ASSERT1(pkey);
|
||||
|
||||
if (ssl->cert->pkey == pkey)
|
||||
return 1;
|
||||
|
||||
if (ssl->cert->pkey)
|
||||
EVP_PKEY_free(ssl->cert->pkey);
|
||||
|
||||
ssl->cert->pkey = pkey;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load private key into the SSL context
|
||||
*/
|
||||
int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx,
|
||||
const unsigned char *d, long len)
|
||||
{
|
||||
int ret;
|
||||
EVP_PKEY *pk;
|
||||
|
||||
pk = d2i_PrivateKey(0, NULL, &d, len);
|
||||
if (!pk) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL");
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
ret = SSL_CTX_use_PrivateKey(ctx, pk);
|
||||
if (!ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_PrivateKey() return %d", ret);
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
failed2:
|
||||
EVP_PKEY_free(pk);
|
||||
failed1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load private key into the SSL
|
||||
*/
|
||||
int SSL_use_PrivateKey_ASN1(int type, SSL *ssl,
|
||||
const unsigned char *d, long len)
|
||||
{
|
||||
int ret;
|
||||
EVP_PKEY *pk;
|
||||
|
||||
pk = d2i_PrivateKey(0, NULL, &d, len);
|
||||
if (!pk) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL");
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
ret = SSL_use_PrivateKey(ssl, pk);
|
||||
if (!ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_PrivateKey() return %d", ret);
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
failed2:
|
||||
EVP_PKEY_free(pk);
|
||||
failed1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load the private key file into SSL context
|
||||
*/
|
||||
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load the private key file into SSL
|
||||
*/
|
||||
int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load the RSA ASN1 private key into SSL context
|
||||
*/
|
||||
int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len)
|
||||
{
|
||||
return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len);
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_stack.h"
|
||||
#include "ssl_dbg.h"
|
||||
#include "ssl_port.h"
|
||||
|
||||
#ifndef CONFIG_MIN_NODES
|
||||
#define MIN_NODES 4
|
||||
#else
|
||||
#define MIN_NODES CONFIG_MIN_NODES
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief create a openssl stack object
|
||||
*/
|
||||
OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c)
|
||||
{
|
||||
OPENSSL_STACK *stack;
|
||||
char **data;
|
||||
|
||||
stack = ssl_mem_zalloc(sizeof(OPENSSL_STACK));
|
||||
if (!stack) {
|
||||
SSL_DEBUG(SSL_STACK_ERROR_LEVEL, "no enough memory > (stack)");
|
||||
goto no_mem1;
|
||||
}
|
||||
|
||||
data = ssl_mem_zalloc(sizeof(*data) * MIN_NODES);
|
||||
if (!data) {
|
||||
SSL_DEBUG(SSL_STACK_ERROR_LEVEL, "no enough memory > (data)");
|
||||
goto no_mem2;
|
||||
}
|
||||
|
||||
stack->data = data;
|
||||
stack->num_alloc = MIN_NODES;
|
||||
stack->c = c;
|
||||
|
||||
return stack;
|
||||
|
||||
no_mem2:
|
||||
ssl_mem_free(stack);
|
||||
no_mem1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create a NULL function openssl stack object
|
||||
*/
|
||||
OPENSSL_STACK *OPENSSL_sk_new_null(void)
|
||||
{
|
||||
return OPENSSL_sk_new((OPENSSL_sk_compfunc)NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free openssl stack object
|
||||
*/
|
||||
void OPENSSL_sk_free(OPENSSL_STACK *stack)
|
||||
{
|
||||
SSL_ASSERT3(stack);
|
||||
|
||||
ssl_mem_free(stack->data);
|
||||
ssl_mem_free(stack);
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_x509.h"
|
||||
#include "ssl_methods.h"
|
||||
#include "ssl_dbg.h"
|
||||
#include "ssl_port.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* @brief show X509 certification information
|
||||
*/
|
||||
int __X509_show_info(X509 *x)
|
||||
{
|
||||
return X509_METHOD_CALL(show_info, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create a X509 certification object according to input X509 certification
|
||||
*/
|
||||
X509* __X509_new(X509 *ix)
|
||||
{
|
||||
int ret;
|
||||
X509 *x;
|
||||
|
||||
x = ssl_mem_zalloc(sizeof(X509));
|
||||
if (!x) {
|
||||
SSL_DEBUG(SSL_X509_ERROR_LEVEL, "no enough memory > (x)");
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (ix)
|
||||
x->method = ix->method;
|
||||
else
|
||||
x->method = X509_method();
|
||||
|
||||
ret = X509_METHOD_CALL(new, x, ix);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(new) return %d", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return x;
|
||||
|
||||
failed:
|
||||
ssl_mem_free(x);
|
||||
no_mem:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create a X509 certification object
|
||||
*/
|
||||
X509* X509_new(void)
|
||||
{
|
||||
return __X509_new(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free a X509 certification object
|
||||
*/
|
||||
void X509_free(X509 *x)
|
||||
{
|
||||
SSL_ASSERT3(x);
|
||||
|
||||
X509_METHOD_CALL(free, x);
|
||||
|
||||
ssl_mem_free(x);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief load a character certification context into system context. If '*cert' is pointed to the
|
||||
* certification, then load certification into it. Or create a new X509 certification object
|
||||
*/
|
||||
X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len)
|
||||
{
|
||||
int m = 0;
|
||||
int ret;
|
||||
X509 *x;
|
||||
|
||||
SSL_ASSERT2(buffer);
|
||||
SSL_ASSERT2(len);
|
||||
|
||||
if (cert && *cert) {
|
||||
x = *cert;
|
||||
} else {
|
||||
x = X509_new();
|
||||
if (!x) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL");
|
||||
goto failed1;
|
||||
}
|
||||
m = 1;
|
||||
}
|
||||
|
||||
ret = X509_METHOD_CALL(load, x, buffer, len);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret);
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
return x;
|
||||
|
||||
failed2:
|
||||
if (m)
|
||||
X509_free(x);
|
||||
failed1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return SSL X509 verify parameters
|
||||
*/
|
||||
|
||||
X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
|
||||
{
|
||||
return &ssl->param;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set X509 host verification flags
|
||||
*/
|
||||
|
||||
int X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
|
||||
unsigned long flags)
|
||||
{
|
||||
/* flags not supported yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief clear X509 host verification flags
|
||||
*/
|
||||
|
||||
int X509_VERIFY_PARAM_clear_hostflags(X509_VERIFY_PARAM *param,
|
||||
unsigned long flags)
|
||||
{
|
||||
/* flags not supported yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set SSL context client CA certification
|
||||
*/
|
||||
int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
|
||||
{
|
||||
SSL_ASSERT1(ctx);
|
||||
SSL_ASSERT1(x);
|
||||
assert(ctx);
|
||||
if (ctx->client_CA == x)
|
||||
return 1;
|
||||
|
||||
X509_free(ctx->client_CA);
|
||||
|
||||
ctx->client_CA = x;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add CA client certification into the SSL
|
||||
*/
|
||||
int SSL_CTX_add_client_CA_ASN1(SSL_CTX *ctx, int len,
|
||||
const unsigned char *d)
|
||||
{
|
||||
X509 *x;
|
||||
|
||||
x = d2i_X509(NULL, d, len);
|
||||
if (!x) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
|
||||
return 0;
|
||||
}
|
||||
SSL_ASSERT1(ctx);
|
||||
|
||||
X509_free(ctx->client_CA);
|
||||
|
||||
ctx->client_CA = x;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add CA client certification into the SSL
|
||||
*/
|
||||
int SSL_add_client_CA(SSL *ssl, X509 *x)
|
||||
{
|
||||
SSL_ASSERT1(ssl);
|
||||
SSL_ASSERT1(x);
|
||||
|
||||
if (ssl->client_CA == x)
|
||||
return 1;
|
||||
|
||||
X509_free(ssl->client_CA);
|
||||
|
||||
ssl->client_CA = x;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set the SSL context certification
|
||||
*/
|
||||
int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
|
||||
{
|
||||
SSL_ASSERT1(ctx);
|
||||
SSL_ASSERT1(x);
|
||||
|
||||
if (ctx->cert->x509 == x)
|
||||
return 1;
|
||||
|
||||
X509_free(ctx->cert->x509);
|
||||
|
||||
ctx->cert->x509 = x;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set the SSL certification
|
||||
*/
|
||||
int SSL_use_certificate(SSL *ssl, X509 *x)
|
||||
{
|
||||
SSL_ASSERT1(ssl);
|
||||
SSL_ASSERT1(x);
|
||||
|
||||
if (ssl->cert->x509 == x)
|
||||
return 1;
|
||||
|
||||
X509_free(ssl->cert->x509);
|
||||
|
||||
ssl->cert->x509 = x;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the SSL certification point
|
||||
*/
|
||||
X509 *SSL_get_certificate(const SSL *ssl)
|
||||
{
|
||||
SSL_ASSERT2(ssl);
|
||||
|
||||
return ssl->cert->x509;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load certification into the SSL context
|
||||
*/
|
||||
int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len,
|
||||
const unsigned char *d)
|
||||
{
|
||||
int ret;
|
||||
X509 *x;
|
||||
|
||||
x = d2i_X509(NULL, d, len);
|
||||
if (!x) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
ret = SSL_CTX_use_certificate(ctx, x);
|
||||
if (!ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret);
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
failed2:
|
||||
X509_free(x);
|
||||
failed1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load certification into the SSL
|
||||
*/
|
||||
int SSL_use_certificate_ASN1(SSL *ssl, int len,
|
||||
const unsigned char *d)
|
||||
{
|
||||
int ret;
|
||||
X509 *x;
|
||||
|
||||
x = d2i_X509(NULL, d, len);
|
||||
if (!x) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
ret = SSL_use_certificate(ssl, x);
|
||||
if (!ret) {
|
||||
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_certificate() return %d", ret);
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
failed2:
|
||||
X509_free(x);
|
||||
failed1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load the certification file into SSL context
|
||||
*/
|
||||
int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief load the certification file into SSL
|
||||
*/
|
||||
int SSL_use_certificate_file(SSL *ssl, const char *file, int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get peer certification
|
||||
*/
|
||||
X509 *SSL_get_peer_certificate(const SSL *ssl)
|
||||
{
|
||||
SSL_ASSERT2(ssl);
|
||||
|
||||
return ssl->session->peer;
|
||||
}
|
||||
|
||||
int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx)
|
||||
{
|
||||
return X509_V_ERR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *X509_verify_cert_error_string(long n)
|
||||
{
|
||||
return "unknown";
|
||||
}
|
|
@ -1,907 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_pm.h"
|
||||
#include "ssl_port.h"
|
||||
#include "ssl_dbg.h"
|
||||
|
||||
/* mbedtls include */
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/certs.h"
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#define X509_INFO_STRING_LENGTH 8192
|
||||
|
||||
struct ssl_pm
|
||||
{
|
||||
/* local socket file description */
|
||||
mbedtls_net_context fd;
|
||||
/* remote client socket file description */
|
||||
mbedtls_net_context cl_fd;
|
||||
|
||||
mbedtls_ssl_config conf;
|
||||
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
mbedtls_ssl_context ssl;
|
||||
|
||||
mbedtls_entropy_context entropy;
|
||||
|
||||
SSL *owner;
|
||||
};
|
||||
|
||||
struct x509_pm
|
||||
{
|
||||
mbedtls_x509_crt *x509_crt;
|
||||
|
||||
mbedtls_x509_crt *ex_crt;
|
||||
};
|
||||
|
||||
struct pkey_pm
|
||||
{
|
||||
mbedtls_pk_context *pkey;
|
||||
|
||||
mbedtls_pk_context *ex_pkey;
|
||||
};
|
||||
|
||||
unsigned int max_content_len;
|
||||
|
||||
/*********************************************************************************************/
|
||||
/************************************ SSL arch interface *************************************/
|
||||
|
||||
//#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG
|
||||
|
||||
/* mbedtls debug level */
|
||||
#define MBEDTLS_DEBUG_LEVEL 4
|
||||
|
||||
/**
|
||||
* @brief mbedtls debug function
|
||||
*/
|
||||
static void ssl_platform_debug(void *ctx, int level,
|
||||
const char *file, int line,
|
||||
const char *str)
|
||||
{
|
||||
/* Shorten 'file' from the whole file path to just the filename
|
||||
|
||||
This is a bit wasteful because the macros are compiled in with
|
||||
the full _FILE_ path in each case.
|
||||
*/
|
||||
// char *file_sep = rindex(file, '/');
|
||||
// if(file_sep)
|
||||
// file = file_sep + 1;
|
||||
|
||||
printf("%s:%d %s", file, line, str);
|
||||
}
|
||||
//#endif
|
||||
|
||||
/**
|
||||
* @brief create SSL low-level object
|
||||
*/
|
||||
int ssl_pm_new(SSL *ssl)
|
||||
{
|
||||
struct ssl_pm *ssl_pm;
|
||||
int ret;
|
||||
|
||||
const unsigned char pers[] = "OpenSSL PM";
|
||||
size_t pers_len = sizeof(pers);
|
||||
|
||||
int endpoint;
|
||||
int version;
|
||||
|
||||
const SSL_METHOD *method = ssl->method;
|
||||
|
||||
ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm));
|
||||
if (!ssl_pm) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (ssl_pm)");
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
ssl_pm->owner = ssl;
|
||||
|
||||
if (!ssl->ctx->read_buffer_len)
|
||||
ssl->ctx->read_buffer_len = 2048;
|
||||
|
||||
max_content_len = ssl->ctx->read_buffer_len;
|
||||
// printf("ssl->ctx->read_buffer_len = %d ++++++++++++++++++++\n", ssl->ctx->read_buffer_len);
|
||||
|
||||
mbedtls_net_init(&ssl_pm->fd);
|
||||
mbedtls_net_init(&ssl_pm->cl_fd);
|
||||
|
||||
mbedtls_ssl_config_init(&ssl_pm->conf);
|
||||
mbedtls_ctr_drbg_init(&ssl_pm->ctr_drbg);
|
||||
mbedtls_entropy_init(&ssl_pm->entropy);
|
||||
mbedtls_ssl_init(&ssl_pm->ssl);
|
||||
|
||||
ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ctr_drbg_seed() return -0x%x", -ret);
|
||||
goto mbedtls_err1;
|
||||
}
|
||||
|
||||
if (method->endpoint) {
|
||||
endpoint = MBEDTLS_SSL_IS_SERVER;
|
||||
} else {
|
||||
endpoint = MBEDTLS_SSL_IS_CLIENT;
|
||||
}
|
||||
ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_config_defaults() return -0x%x", -ret);
|
||||
goto mbedtls_err2;
|
||||
}
|
||||
|
||||
if (TLS_ANY_VERSION != ssl->version) {
|
||||
if (TLS1_2_VERSION == ssl->version)
|
||||
version = MBEDTLS_SSL_MINOR_VERSION_3;
|
||||
else if (TLS1_1_VERSION == ssl->version)
|
||||
version = MBEDTLS_SSL_MINOR_VERSION_2;
|
||||
else if (TLS1_VERSION == ssl->version)
|
||||
version = MBEDTLS_SSL_MINOR_VERSION_1;
|
||||
else
|
||||
version = MBEDTLS_SSL_MINOR_VERSION_0;
|
||||
|
||||
mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version);
|
||||
mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version);
|
||||
} else {
|
||||
mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
|
||||
mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0);
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg);
|
||||
|
||||
//#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG
|
||||
// mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL);
|
||||
// mbedtls_ssl_conf_dbg(&ssl_pm->conf, ssl_platform_debug, NULL);
|
||||
//#else
|
||||
mbedtls_ssl_conf_dbg(&ssl_pm->conf, ssl_platform_debug, NULL);
|
||||
//#endif
|
||||
|
||||
ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_setup() return -0x%x", -ret);
|
||||
goto mbedtls_err2;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
ssl->ssl_pm = ssl_pm;
|
||||
|
||||
return 0;
|
||||
|
||||
mbedtls_err2:
|
||||
mbedtls_ssl_config_free(&ssl_pm->conf);
|
||||
mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg);
|
||||
mbedtls_err1:
|
||||
mbedtls_entropy_free(&ssl_pm->entropy);
|
||||
ssl_mem_free(ssl_pm);
|
||||
no_mem:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free SSL low-level object
|
||||
*/
|
||||
void ssl_pm_free(SSL *ssl)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg);
|
||||
mbedtls_entropy_free(&ssl_pm->entropy);
|
||||
mbedtls_ssl_config_free(&ssl_pm->conf);
|
||||
mbedtls_ssl_free(&ssl_pm->ssl);
|
||||
|
||||
ssl_mem_free(ssl_pm);
|
||||
ssl->ssl_pm = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief reload SSL low-level certification object
|
||||
*/
|
||||
static int ssl_pm_reload_crt(SSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
int mode;
|
||||
struct ssl_pm *ssl_pm = ssl->ssl_pm;
|
||||
struct x509_pm *ca_pm = (struct x509_pm *)ssl->client_CA->x509_pm;
|
||||
|
||||
struct pkey_pm *pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm;
|
||||
struct x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm;
|
||||
|
||||
if (ssl->verify_mode == SSL_VERIFY_PEER)
|
||||
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
else if (ssl->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
|
||||
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
else if (ssl->verify_mode == SSL_VERIFY_CLIENT_ONCE)
|
||||
mode = MBEDTLS_SSL_VERIFY_UNSET;
|
||||
else
|
||||
mode = MBEDTLS_SSL_VERIFY_NONE;
|
||||
|
||||
mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode);
|
||||
|
||||
if (ca_pm->x509_crt) {
|
||||
mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL);
|
||||
} else if (ca_pm->ex_crt) {
|
||||
mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->ex_crt, NULL);
|
||||
}
|
||||
|
||||
if (crt_pm->x509_crt && pkey_pm->pkey) {
|
||||
ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->x509_crt, pkey_pm->pkey);
|
||||
} else if (crt_pm->ex_crt && pkey_pm->ex_pkey) {
|
||||
ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->ex_crt, pkey_pm->ex_pkey);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_conf_own_cert() return -0x%x", -ret);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the mbedtls SSL handshake instead of mbedtls_ssl_handshake.
|
||||
* We can add debug here.
|
||||
*/
|
||||
static int mbedtls_handshake( mbedtls_ssl_context *ssl )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
|
||||
ret = mbedtls_ssl_handshake_step(ssl);
|
||||
|
||||
lwsl_info("%s: ssl ret -%x state %d\n", __func__, -ret, ssl->state);
|
||||
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
int ssl_pm_handshake(SSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
ssl->err = 0;
|
||||
errno = 0;
|
||||
|
||||
ret = ssl_pm_reload_crt(ssl);
|
||||
if (ret) {
|
||||
printf("%s: cert reload failed\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ssl_pm->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
|
||||
ssl_speed_up_enter();
|
||||
|
||||
/* mbedtls return codes
|
||||
* 0 = successful, or MBEDTLS_ERR_SSL_WANT_READ/WRITE
|
||||
* anything else = death
|
||||
*/
|
||||
ret = mbedtls_handshake(&ssl_pm->ssl);
|
||||
ssl_speed_up_exit();
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* OpenSSL return codes:
|
||||
* 0 = did not complete, but may be retried
|
||||
* 1 = successfully completed
|
||||
* <0 = death
|
||||
*/
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ssl->err = ret;
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_handshake() return -0x%x", -ret);
|
||||
return 0; /* OpenSSL: did not complete but may be retried */
|
||||
}
|
||||
|
||||
if (ret == 0) { /* successful */
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm;
|
||||
|
||||
x509_pm->ex_crt = (mbedtls_x509_crt *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl);
|
||||
return 1; /* openssl successful */
|
||||
}
|
||||
|
||||
if (errno == 11) {
|
||||
ssl->err = ret == MBEDTLS_ERR_SSL_WANT_READ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("%s: mbedtls_ssl_handshake() returned -0x%x\n", __func__, -ret);
|
||||
|
||||
/* it's had it */
|
||||
|
||||
ssl->err = SSL_ERROR_SYSCALL;
|
||||
|
||||
return -1; /* openssl death */
|
||||
}
|
||||
|
||||
mbedtls_x509_crt *
|
||||
ssl_ctx_get_mbedtls_x509_crt(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)ssl_ctx->cert->x509->x509_pm;
|
||||
|
||||
if (!x509_pm)
|
||||
return NULL;
|
||||
|
||||
return x509_pm->x509_crt;
|
||||
}
|
||||
|
||||
mbedtls_x509_crt *
|
||||
ssl_get_peer_mbedtls_x509_crt(SSL *ssl)
|
||||
{
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm;
|
||||
|
||||
if (!x509_pm)
|
||||
return NULL;
|
||||
|
||||
return x509_pm->ex_crt;
|
||||
}
|
||||
|
||||
int ssl_pm_shutdown(SSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
ret = mbedtls_ssl_close_notify(&ssl_pm->ssl);
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_close_notify() return -0x%x", -ret);
|
||||
if (ret == MBEDTLS_ERR_NET_CONN_RESET)
|
||||
ssl->err = SSL_ERROR_SYSCALL;
|
||||
ret = -1; /* OpenSSL: "Call SSL_get_error with the return value to find the reason */
|
||||
} else {
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm;
|
||||
|
||||
x509_pm->ex_crt = NULL;
|
||||
ret = 1; /* OpenSSL: "The shutdown was successfully completed"
|
||||
...0 means retry */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ssl_pm_clear(SSL *ssl)
|
||||
{
|
||||
return ssl_pm_shutdown(ssl);
|
||||
}
|
||||
|
||||
|
||||
int ssl_pm_read(SSL *ssl, void *buffer, int len)
|
||||
{
|
||||
int ret;
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len);
|
||||
if (ret < 0) {
|
||||
// lwsl_notice("%s: mbedtls_ssl_read says -0x%x\n", __func__, -ret);
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret);
|
||||
if (ret == MBEDTLS_ERR_NET_CONN_RESET ||
|
||||
ret <= MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) /* fatal errors */
|
||||
ssl->err = SSL_ERROR_SYSCALL;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns -1, or the length sent.
|
||||
* If -1, then you need to find out if the error was
|
||||
* fatal or recoverable using SSL_get_error()
|
||||
*/
|
||||
int ssl_pm_send(SSL *ssl, const void *buffer, int len)
|
||||
{
|
||||
int ret;
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len);
|
||||
/*
|
||||
* We can get a positive number, which may be less than len... that
|
||||
* much was sent successfully and you can call again to send more.
|
||||
*
|
||||
* We can get a negative mbedtls error code... if WANT_WRITE or WANT_READ,
|
||||
* it's nonfatal and means it should be retried as-is. If something else,
|
||||
* it's fatal actually.
|
||||
*
|
||||
* If this function returns something other than a positive value or
|
||||
* MBEDTLS_ERR_SSL_WANT_READ/WRITE, the ssl context becomes unusable, and
|
||||
* you should either free it or call mbedtls_ssl_session_reset() on it
|
||||
* before re-using it for a new connection; the current connection must
|
||||
* be closed.
|
||||
*
|
||||
* When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ, it must be
|
||||
* called later with the same arguments, until it returns a positive value.
|
||||
*/
|
||||
|
||||
if (ret < 0) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_write() return -0x%x", -ret);
|
||||
switch (ret) {
|
||||
case MBEDTLS_ERR_NET_SEND_FAILED:
|
||||
case MBEDTLS_ERR_NET_CONN_RESET:
|
||||
ssl->err = SSL_ERROR_SYSCALL;
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
ssl->err = SSL_ERROR_WANT_WRITE;
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
ssl->err = SSL_ERROR_WANT_READ;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ssl_pm_pending(const SSL *ssl)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
return mbedtls_ssl_get_bytes_avail(&ssl_pm->ssl);
|
||||
}
|
||||
|
||||
void ssl_pm_set_fd(SSL *ssl, int fd, int mode)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
ssl_pm->fd.fd = fd;
|
||||
}
|
||||
|
||||
int ssl_pm_get_fd(const SSL *ssl, int mode)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
return ssl_pm->fd.fd;
|
||||
}
|
||||
|
||||
OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl)
|
||||
{
|
||||
OSSL_HANDSHAKE_STATE state;
|
||||
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
switch (ssl_pm->ssl.state)
|
||||
{
|
||||
case MBEDTLS_SSL_CLIENT_HELLO:
|
||||
state = TLS_ST_CW_CLNT_HELLO;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_HELLO:
|
||||
state = TLS_ST_SW_SRVR_HELLO;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_CERTIFICATE:
|
||||
state = TLS_ST_SW_CERT;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_HELLO_DONE:
|
||||
state = TLS_ST_SW_SRVR_DONE;
|
||||
break;
|
||||
case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
|
||||
state = TLS_ST_CW_KEY_EXCH;
|
||||
break;
|
||||
case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
|
||||
state = TLS_ST_CW_CHANGE;
|
||||
break;
|
||||
case MBEDTLS_SSL_CLIENT_FINISHED:
|
||||
state = TLS_ST_CW_FINISHED;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
|
||||
state = TLS_ST_SW_CHANGE;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_FINISHED:
|
||||
state = TLS_ST_SW_FINISHED;
|
||||
break;
|
||||
case MBEDTLS_SSL_CLIENT_CERTIFICATE:
|
||||
state = TLS_ST_CW_CERT;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
|
||||
state = TLS_ST_SR_KEY_EXCH;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET:
|
||||
state = TLS_ST_SW_SESSION_TICKET;
|
||||
break;
|
||||
case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT:
|
||||
state = TLS_ST_SW_CERT_REQ;
|
||||
break;
|
||||
case MBEDTLS_SSL_HANDSHAKE_OVER:
|
||||
state = TLS_ST_OK;
|
||||
break;
|
||||
default :
|
||||
state = TLS_ST_BEFORE;
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
int x509_pm_show_info(X509 *x)
|
||||
{
|
||||
int ret;
|
||||
char *buf;
|
||||
mbedtls_x509_crt *x509_crt;
|
||||
struct x509_pm *x509_pm = x->x509_pm;
|
||||
|
||||
if (x509_pm->x509_crt)
|
||||
x509_crt = x509_pm->x509_crt;
|
||||
else if (x509_pm->ex_crt)
|
||||
x509_crt = x509_pm->ex_crt;
|
||||
else
|
||||
x509_crt = NULL;
|
||||
|
||||
if (!x509_crt)
|
||||
return -1;
|
||||
|
||||
buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH);
|
||||
if (!buf) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (buf)");
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt);
|
||||
if (ret <= 0) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_info() return -0x%x", -ret);
|
||||
goto mbedtls_err1;
|
||||
}
|
||||
|
||||
buf[ret] = 0;
|
||||
|
||||
ssl_mem_free(buf);
|
||||
|
||||
SSL_DEBUG(SSL_DEBUG_ON, "%s", buf);
|
||||
|
||||
return 0;
|
||||
|
||||
mbedtls_err1:
|
||||
ssl_mem_free(buf);
|
||||
no_mem:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int x509_pm_new(X509 *x, X509 *m_x)
|
||||
{
|
||||
struct x509_pm *x509_pm;
|
||||
|
||||
x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm));
|
||||
if (!x509_pm) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm)");
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
x->x509_pm = x509_pm;
|
||||
|
||||
if (m_x) {
|
||||
struct x509_pm *m_x509_pm = (struct x509_pm *)m_x->x509_pm;
|
||||
|
||||
x509_pm->ex_crt = m_x509_pm->x509_crt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void x509_pm_free(X509 *x)
|
||||
{
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm;
|
||||
|
||||
if (x509_pm->x509_crt) {
|
||||
mbedtls_x509_crt_free(x509_pm->x509_crt);
|
||||
|
||||
ssl_mem_free(x509_pm->x509_crt);
|
||||
x509_pm->x509_crt = NULL;
|
||||
}
|
||||
|
||||
ssl_mem_free(x->x509_pm);
|
||||
x->x509_pm = NULL;
|
||||
}
|
||||
|
||||
int x509_pm_load(X509 *x, const unsigned char *buffer, int len)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *load_buf;
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm;
|
||||
|
||||
if (x509_pm->x509_crt)
|
||||
mbedtls_x509_crt_free(x509_pm->x509_crt);
|
||||
|
||||
if (!x509_pm->x509_crt) {
|
||||
x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt));
|
||||
if (!x509_pm->x509_crt) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)");
|
||||
goto no_mem;
|
||||
}
|
||||
}
|
||||
|
||||
mbedtls_x509_crt_init(x509_pm->x509_crt);
|
||||
if (buffer[0] != 0x30) {
|
||||
load_buf = ssl_mem_malloc(len + 1);
|
||||
if (!load_buf) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ssl_memcpy(load_buf, buffer, len);
|
||||
load_buf[len] = '\0';
|
||||
|
||||
ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1);
|
||||
ssl_mem_free(load_buf);
|
||||
} else {
|
||||
printf("parsing as der\n");
|
||||
|
||||
ret = mbedtls_x509_crt_parse_der(x509_pm->x509_crt, buffer, len);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
printf("mbedtls_x509_crt_parse return -0x%x", -ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
mbedtls_x509_crt_free(x509_pm->x509_crt);
|
||||
ssl_mem_free(x509_pm->x509_crt);
|
||||
x509_pm->x509_crt = NULL;
|
||||
no_mem:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey)
|
||||
{
|
||||
struct pkey_pm *pkey_pm;
|
||||
|
||||
pkey_pm = ssl_mem_zalloc(sizeof(struct pkey_pm));
|
||||
if (!pkey_pm)
|
||||
return -1;
|
||||
|
||||
pk->pkey_pm = pkey_pm;
|
||||
|
||||
if (m_pkey) {
|
||||
struct pkey_pm *m_pkey_pm = (struct pkey_pm *)m_pkey->pkey_pm;
|
||||
|
||||
pkey_pm->ex_pkey = m_pkey_pm->pkey;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pkey_pm_free(EVP_PKEY *pk)
|
||||
{
|
||||
struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm;
|
||||
|
||||
if (pkey_pm->pkey) {
|
||||
mbedtls_pk_free(pkey_pm->pkey);
|
||||
|
||||
ssl_mem_free(pkey_pm->pkey);
|
||||
pkey_pm->pkey = NULL;
|
||||
}
|
||||
|
||||
ssl_mem_free(pk->pkey_pm);
|
||||
pk->pkey_pm = NULL;
|
||||
}
|
||||
|
||||
int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *load_buf;
|
||||
struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm;
|
||||
|
||||
if (pkey_pm->pkey)
|
||||
mbedtls_pk_free(pkey_pm->pkey);
|
||||
|
||||
if (!pkey_pm->pkey) {
|
||||
pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context));
|
||||
if (!pkey_pm->pkey) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (pkey_pm->pkey)");
|
||||
goto no_mem;
|
||||
}
|
||||
}
|
||||
|
||||
load_buf = ssl_mem_malloc(len + 1);
|
||||
if (!load_buf) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ssl_memcpy(load_buf, buffer, len);
|
||||
load_buf[len] = '\0';
|
||||
|
||||
mbedtls_pk_init(pkey_pm->pkey);
|
||||
|
||||
ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0);
|
||||
ssl_mem_free(load_buf);
|
||||
|
||||
if (ret) {
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_pk_parse_key return -0x%x", -ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
mbedtls_pk_free(pkey_pm->pkey);
|
||||
ssl_mem_free(pkey_pm->pkey);
|
||||
pkey_pm->pkey = NULL;
|
||||
no_mem:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ssl_pm_set_bufflen(SSL *ssl, int len)
|
||||
{
|
||||
max_content_len = len;
|
||||
}
|
||||
|
||||
long ssl_pm_get_verify_result(const SSL *ssl)
|
||||
{
|
||||
uint32_t ret;
|
||||
long verify_result;
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl);
|
||||
if (!ret)
|
||||
return X509_V_OK;
|
||||
|
||||
if (ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED ||
|
||||
(ret & MBEDTLS_X509_BADCRL_NOT_TRUSTED))
|
||||
verify_result = X509_V_ERR_INVALID_CA;
|
||||
|
||||
else if (ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
|
||||
verify_result = X509_V_ERR_HOSTNAME_MISMATCH;
|
||||
|
||||
else if ((ret & MBEDTLS_X509_BADCERT_BAD_KEY) ||
|
||||
(ret & MBEDTLS_X509_BADCRL_BAD_KEY))
|
||||
verify_result = X509_V_ERR_CA_KEY_TOO_SMALL;
|
||||
|
||||
else if ((ret & MBEDTLS_X509_BADCERT_BAD_MD) ||
|
||||
(ret & MBEDTLS_X509_BADCRL_BAD_MD))
|
||||
verify_result = X509_V_ERR_CA_MD_TOO_WEAK;
|
||||
|
||||
else if ((ret & MBEDTLS_X509_BADCERT_FUTURE) ||
|
||||
(ret & MBEDTLS_X509_BADCRL_FUTURE))
|
||||
verify_result = X509_V_ERR_CERT_NOT_YET_VALID;
|
||||
|
||||
else if ((ret & MBEDTLS_X509_BADCERT_EXPIRED) ||
|
||||
(ret & MBEDTLS_X509_BADCRL_EXPIRED))
|
||||
verify_result = X509_V_ERR_CERT_HAS_EXPIRED;
|
||||
|
||||
else
|
||||
verify_result = X509_V_ERR_UNSPECIFIED;
|
||||
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL,
|
||||
"mbedtls_ssl_get_verify_result() return 0x%x", ret);
|
||||
|
||||
return verify_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set expected hostname on peer cert CN
|
||||
*/
|
||||
|
||||
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
|
||||
const char *name, size_t namelen)
|
||||
{
|
||||
SSL *ssl = (SSL *)((char *)param - offsetof(SSL, param));
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
char *name_cstr = NULL;
|
||||
|
||||
if (namelen) {
|
||||
name_cstr = malloc(namelen + 1);
|
||||
if (!name_cstr)
|
||||
return 0;
|
||||
memcpy(name_cstr, name, namelen);
|
||||
name_cstr[namelen] = '\0';
|
||||
name = name_cstr;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_hostname(&ssl_pm->ssl, name);
|
||||
|
||||
if (namelen)
|
||||
free(name_cstr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _ssl_set_alpn_list(const SSL *ssl)
|
||||
{
|
||||
if (ssl->alpn_protos) {
|
||||
if (mbedtls_ssl_conf_alpn_protocols(&((struct ssl_pm *)(ssl->ssl_pm))->conf, ssl->alpn_protos))
|
||||
fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols failed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
if (!ssl->ctx->alpn_protos)
|
||||
return;
|
||||
if (mbedtls_ssl_conf_alpn_protocols(&((struct ssl_pm *)(ssl->ssl_pm))->conf, ssl->ctx->alpn_protos))
|
||||
fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols failed\n");
|
||||
}
|
||||
|
||||
void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
|
||||
unsigned int *len)
|
||||
{
|
||||
const char *alp = mbedtls_ssl_get_alpn_protocol(&((struct ssl_pm *)(ssl->ssl_pm))->ssl);
|
||||
|
||||
*data = (const unsigned char *)alp;
|
||||
if (alp)
|
||||
*len = strlen(alp);
|
||||
else
|
||||
*len = 0;
|
||||
}
|
||||
|
||||
int SSL_set_sni_callback(SSL *ssl, int(*cb)(void *, mbedtls_ssl_context *,
|
||||
const unsigned char *, size_t), void *param)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
mbedtls_ssl_conf_sni(&ssl_pm->conf, cb, param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL *SSL_SSL_from_mbedtls_ssl_context(mbedtls_ssl_context *msc)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)((char *)msc - offsetof(struct ssl_pm, ssl));
|
||||
|
||||
return ssl_pm->owner;
|
||||
}
|
||||
|
||||
#include "ssl_cert.h"
|
||||
|
||||
void SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = ssl->ssl_pm;
|
||||
struct x509_pm *x509_pm = (struct x509_pm *)ctx->cert->x509->x509_pm;
|
||||
struct x509_pm *x509_pm_ca = (struct x509_pm *)ctx->client_CA->x509_pm;
|
||||
|
||||
struct pkey_pm *pkey_pm = (struct pkey_pm *)ctx->cert->pkey->pkey_pm;
|
||||
int mode;
|
||||
|
||||
if (ssl->cert)
|
||||
ssl_cert_free(ssl->cert);
|
||||
ssl->ctx = ctx;
|
||||
ssl->cert = __ssl_cert_new(ctx->cert);
|
||||
|
||||
if (ctx->verify_mode == SSL_VERIFY_PEER)
|
||||
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
else if (ctx->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
|
||||
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
else if (ctx->verify_mode == SSL_VERIFY_CLIENT_ONCE)
|
||||
mode = MBEDTLS_SSL_VERIFY_UNSET;
|
||||
else
|
||||
mode = MBEDTLS_SSL_VERIFY_NONE;
|
||||
|
||||
// printf("ssl: %p, client ca x509_crt %p, mbedtls mode %d\n", ssl, x509_pm_ca->x509_crt, mode);
|
||||
|
||||
/* apply new ctx cert to ssl */
|
||||
|
||||
ssl->verify_mode = ctx->verify_mode;
|
||||
|
||||
mbedtls_ssl_set_hs_ca_chain(&ssl_pm->ssl, x509_pm_ca->x509_crt, NULL);
|
||||
mbedtls_ssl_set_hs_own_cert(&ssl_pm->ssl, x509_pm->x509_crt, pkey_pm->pkey);
|
||||
mbedtls_ssl_set_hs_authmode(&ssl_pm->ssl, mode);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ssl_port.h"
|
||||
|
||||
/*********************************************************************************************/
|
||||
/********************************* SSL general interface *************************************/
|
||||
|
||||
void *ssl_mem_zalloc(size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
|
||||
if (p)
|
||||
memset(p, 0, size);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
|
@ -1,281 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 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
|
||||
*
|
||||
* This is included from core/private.h if LWS_WITH_TLS
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
||||
#if defined(USE_WOLFSSL)
|
||||
#if defined(USE_OLD_CYASSL)
|
||||
#if defined(_WIN32)
|
||||
#include <IDE/WIN/user_settings.h>
|
||||
#include <cyassl/ctaocrypt/settings.h>
|
||||
#else
|
||||
#include <cyassl/options.h>
|
||||
#endif
|
||||
#include <cyassl/openssl/ssl.h>
|
||||
#include <cyassl/error-ssl.h>
|
||||
#else
|
||||
#if defined(_WIN32)
|
||||
#include <IDE/WIN/user_settings.h>
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#else
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/openssl/ssl.h>
|
||||
#include <wolfssl/error-ssl.h>
|
||||
#define OPENSSL_NO_TLSEXT
|
||||
#endif /* not USE_OLD_CYASSL */
|
||||
#else /* WOLFSSL */
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
#define OPENSSL_NO_TLSEXT
|
||||
#undef MBEDTLS_CONFIG_FILE
|
||||
#define MBEDTLS_CONFIG_FILE <mbedtls/esp_config.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
|
||||
#else /* not esp32 */
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include <mbedtls/x509_csr.h>
|
||||
#include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
|
||||
#else
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/sha.h>
|
||||
#ifdef LWS_HAVE_OPENSSL_ECDH_H
|
||||
#include <openssl/ecdh.h>
|
||||
#endif
|
||||
#include <openssl/x509v3.h>
|
||||
#endif /* not mbedtls */
|
||||
#if defined(OPENSSL_VERSION_NUMBER)
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x0009080afL)
|
||||
/* later openssl defines this to negate the presence of tlsext... but it was only
|
||||
* introduced at 0.9.8j. Earlier versions don't know it exists so don't
|
||||
* define it... making it look like the feature exists...
|
||||
*/
|
||||
#define OPENSSL_NO_TLSEXT
|
||||
#endif
|
||||
#endif
|
||||
#endif /* not ESP32 */
|
||||
#endif /* not USE_WOLFSSL */
|
||||
|
||||
#endif /* LWS_WITH_TLS */
|
||||
|
||||
enum lws_tls_extant {
|
||||
LWS_TLS_EXTANT_NO,
|
||||
LWS_TLS_EXTANT_YES,
|
||||
LWS_TLS_EXTANT_ALTERNATIVE
|
||||
};
|
||||
|
||||
struct lws_context_per_thread;
|
||||
|
||||
struct lws_tls_ops {
|
||||
int (*fake_POLLIN_for_buffered)(struct lws_context_per_thread *pt);
|
||||
int (*periodic_housekeeping)(struct lws_context *context, time_t now);
|
||||
};
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
||||
typedef SSL lws_tls_conn;
|
||||
typedef SSL_CTX lws_tls_ctx;
|
||||
typedef BIO lws_tls_bio;
|
||||
typedef X509 lws_tls_x509;
|
||||
|
||||
|
||||
#define LWS_SSL_ENABLED(context) (context->tls.use_ssl)
|
||||
|
||||
extern const struct lws_tls_ops tls_ops_openssl, tls_ops_mbedtls;
|
||||
|
||||
struct lws_context_tls {
|
||||
char alpn_discovered[32];
|
||||
const char *alpn_default;
|
||||
time_t last_cert_check_s;
|
||||
};
|
||||
|
||||
struct lws_pt_tls {
|
||||
struct lws *pending_read_list; /* linked list */
|
||||
};
|
||||
|
||||
struct lws_tls_ss_pieces;
|
||||
|
||||
struct alpn_ctx {
|
||||
uint8_t data[23];
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct lws_vhost_tls {
|
||||
lws_tls_ctx *ssl_ctx;
|
||||
lws_tls_ctx *ssl_client_ctx;
|
||||
const char *alpn;
|
||||
struct lws_tls_ss_pieces *ss; /* for acme tls certs */
|
||||
char *alloc_cert_path;
|
||||
char *key_path;
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
lws_tls_x509 *x509_client_CA;
|
||||
#endif
|
||||
char ecdh_curve[16];
|
||||
struct alpn_ctx alpn_ctx;
|
||||
|
||||
int use_ssl;
|
||||
int allow_non_ssl_on_ssl_port;
|
||||
int ssl_info_event_mask;
|
||||
|
||||
unsigned int user_supplied_ssl_ctx:1;
|
||||
unsigned int skipped_certs:1;
|
||||
};
|
||||
|
||||
struct lws_lws_tls {
|
||||
lws_tls_conn *ssl;
|
||||
lws_tls_bio *client_bio;
|
||||
struct lws *pending_read_list_prev, *pending_read_list_next;
|
||||
unsigned int use_ssl;
|
||||
unsigned int redirect_to_https:1;
|
||||
};
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_context_init_alpn(struct lws_vhost *vhost);
|
||||
LWS_EXTERN enum lws_tls_extant
|
||||
lws_tls_use_any_upgrade_check_extant(const char *name);
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_pending(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_close(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_context_destroy(struct lws_context *context);
|
||||
void
|
||||
__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_bio_create(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect1(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_elaborate_error(void);
|
||||
LWS_EXTERN int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
|
||||
LWS_EXTERN int
|
||||
lws_gate_accepts(struct lws_context *context, int on);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_bind_passphrase(lws_tls_ctx *ssl_ctx,
|
||||
const struct lws_context_creation_info *info);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
||||
LWS_EXTERN int
|
||||
lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
|
||||
const char *cert, const char *private_key,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t mem_privkey_len);
|
||||
LWS_EXTERN enum lws_tls_extant
|
||||
lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
|
||||
const char *private_key);
|
||||
LWS_EXTERN int
|
||||
lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
|
||||
const char *inbuf, lws_filepos_t inlen,
|
||||
uint8_t **buf, lws_filepos_t *amount);
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost);
|
||||
#else
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#define lws_tls_acme_sni_cert_destroy(_a)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost);
|
||||
LWS_EXTERN char *
|
||||
lws_ssl_get_error_string(int status, int ret, char *buf, size_t len);
|
||||
|
||||
/*
|
||||
* lws_tls_ abstract backend implementations
|
||||
*/
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_client_cert_verify_config(struct lws_vhost *vh);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost, struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_server_accept(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_server_abort_connection(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
__lws_tls_shutdown(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_client_connect(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_client_create_vhost_context(struct lws_vhost *vh,
|
||||
const struct lws_context_creation_info *info,
|
||||
const char *cipher_list,
|
||||
const char *ca_filepath,
|
||||
const char *cert_filepath,
|
||||
const char *private_key_filepath);
|
||||
|
||||
LWS_EXTERN lws_tls_ctx *
|
||||
lws_tls_ctx_from_wsi(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_get_error(struct lws *wsi, int n);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_context_init_client_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
||||
|
||||
int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
|
||||
|
||||
#endif
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - client-related ssl code independent of backend
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
int
|
||||
lws_ssl_client_connect1(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
int n = 0;
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
n = lws_tls_client_connect(wsi);
|
||||
lws_latency(context, wsi, "SSL_connect hs", n, n > 0);
|
||||
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
return -1;
|
||||
case LWS_SSL_CAPABLE_DONE:
|
||||
return 1; /* connected */
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
|
||||
lws_callback_on_writable(wsi);
|
||||
/* fallthru */
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
|
||||
lwsi_set_state(wsi, LRS_WAITING_SSL);
|
||||
break;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0; /* retry */
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (lwsi_state(wsi) == LRS_WAITING_SSL) {
|
||||
lws_latency_pre(wsi->context, wsi);
|
||||
|
||||
n = lws_tls_client_connect(wsi);
|
||||
lwsl_debug("%s: SSL_connect says %d\n", __func__, n);
|
||||
lws_latency(wsi->context, wsi,
|
||||
"SSL_connect LRS_WAITING_SSL", n, n > 0);
|
||||
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
lws_snprintf(errbuf, len, "client connect failed");
|
||||
return -1;
|
||||
case LWS_SSL_CAPABLE_DONE:
|
||||
break; /* connected */
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
|
||||
lws_callback_on_writable(wsi);
|
||||
/* fallthru */
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
|
||||
lwsi_set_state(wsi, LRS_WAITING_SSL);
|
||||
/* fallthru */
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lws_tls_client_confirm_peer_cert(wsi, errbuf, len))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
const char *ca_filepath = info->ssl_ca_filepath;
|
||||
const char *cipher_list = info->ssl_cipher_list;
|
||||
const char *private_key_filepath = info->ssl_private_key_filepath;
|
||||
const char *cert_filepath = info->ssl_cert_filepath;
|
||||
struct lws wsi;
|
||||
|
||||
if (vhost->options & LWS_SERVER_OPTION_ONLY_RAW)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* for backwards-compatibility default to using ssl_... members, but
|
||||
* if the newer client-specific ones are given, use those
|
||||
*/
|
||||
if (info->client_ssl_cipher_list)
|
||||
cipher_list = info->client_ssl_cipher_list;
|
||||
if (info->client_ssl_cert_filepath)
|
||||
cert_filepath = info->client_ssl_cert_filepath;
|
||||
if (info->client_ssl_private_key_filepath)
|
||||
private_key_filepath = info->client_ssl_private_key_filepath;
|
||||
|
||||
if (info->client_ssl_ca_filepath)
|
||||
ca_filepath = info->client_ssl_ca_filepath;
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
return 0;
|
||||
|
||||
if (vhost->tls.ssl_client_ctx)
|
||||
return 0;
|
||||
|
||||
if (info->provided_client_ssl_ctx) {
|
||||
/* use the provided OpenSSL context if given one */
|
||||
vhost->tls.ssl_client_ctx = info->provided_client_ssl_ctx;
|
||||
/* nothing for lib to delete */
|
||||
vhost->tls.user_supplied_ssl_ctx = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lws_tls_client_create_vhost_context(vhost, info, cipher_list,
|
||||
ca_filepath, cert_filepath,
|
||||
private_key_filepath))
|
||||
return 1;
|
||||
|
||||
lwsl_notice("created client ssl context for %s\n", vhost->name);
|
||||
|
||||
/*
|
||||
* give him a fake wsi with context set, so he can use
|
||||
* lws_get_context() in the callback
|
||||
*/
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.vhost = vhost;
|
||||
wsi.context = vhost->context;
|
||||
|
||||
vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
|
||||
vhost->tls.ssl_client_ctx, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2018 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 "core/private.h"
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
static int
|
||||
alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen, void *arg)
|
||||
{
|
||||
#if !defined(LWS_WITH_MBEDTLS)
|
||||
struct alpn_ctx *alpn_ctx = (struct alpn_ctx *)arg;
|
||||
|
||||
if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data,
|
||||
alpn_ctx->len, in, inlen) !=
|
||||
OPENSSL_NPN_NEGOTIATED)
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
#endif
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
lws_context_init_alpn(struct lws_vhost *vhost)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
const char *alpn_comma = vhost->context->tls.alpn_default;
|
||||
|
||||
if (vhost->tls.alpn)
|
||||
alpn_comma = vhost->tls.alpn;
|
||||
|
||||
lwsl_info(" Server '%s' advertising ALPN: %s\n",
|
||||
vhost->name, alpn_comma);
|
||||
vhost->tls.alpn_ctx.len = lws_alpn_comma_to_openssl(alpn_comma,
|
||||
vhost->tls.alpn_ctx.data,
|
||||
sizeof(vhost->tls.alpn_ctx.data) - 1);
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(vhost->tls.ssl_ctx, alpn_cb, &vhost->tls.alpn_ctx);
|
||||
#else
|
||||
lwsl_err(
|
||||
" HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\n",
|
||||
OPENSSL_VERSION_NUMBER);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_server_conn_alpn(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
const unsigned char *name = NULL;
|
||||
char cstr[10];
|
||||
unsigned len;
|
||||
|
||||
SSL_get0_alpn_selected(wsi->tls.ssl, &name, &len);
|
||||
if (!len) {
|
||||
lwsl_info("no ALPN upgrade\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > sizeof(cstr) - 1)
|
||||
len = sizeof(cstr) - 1;
|
||||
|
||||
memcpy(cstr, name, len);
|
||||
cstr[len] = '\0';
|
||||
|
||||
lwsl_info("negotiated '%s' using ALPN\n", cstr);
|
||||
wsi->tls.use_ssl |= LCCSCF_USE_SSL;
|
||||
|
||||
return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_context_init_server_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
struct lws_context *context = vhost->context;
|
||||
struct lws wsi;
|
||||
|
||||
if (!lws_check_opt(info->options,
|
||||
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
|
||||
vhost->tls.use_ssl = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If he is giving a cert filepath, take it as a sign he wants to use
|
||||
* it on this vhost. User code can leave the cert filepath NULL and
|
||||
* set the LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX option itself, in
|
||||
* which case he's expected to set up the cert himself at
|
||||
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
|
||||
* provides the vhost SSL_CTX * in the user parameter.
|
||||
*/
|
||||
if (info->ssl_cert_filepath)
|
||||
vhost->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX;
|
||||
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN) {
|
||||
|
||||
vhost->tls.use_ssl = lws_check_opt(vhost->options,
|
||||
LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX);
|
||||
|
||||
if (vhost->tls.use_ssl && info->ssl_cipher_list)
|
||||
lwsl_notice(" SSL ciphers: '%s'\n",
|
||||
info->ssl_cipher_list);
|
||||
|
||||
if (vhost->tls.use_ssl)
|
||||
lwsl_notice(" Using SSL mode\n");
|
||||
else
|
||||
lwsl_notice(" Using non-SSL mode\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* give him a fake wsi with context + vhost set, so he can use
|
||||
* lws_get_context() in the callback
|
||||
*/
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.vhost = vhost;
|
||||
wsi.context = context;
|
||||
|
||||
/*
|
||||
* as a server, if we are requiring clients to identify themselves
|
||||
* then set the backend up for it
|
||||
*/
|
||||
if (lws_check_opt(info->options,
|
||||
LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
|
||||
/* Normally SSL listener rejects non-ssl, optionally allow */
|
||||
vhost->tls.allow_non_ssl_on_ssl_port = 1;
|
||||
|
||||
/*
|
||||
* give user code a chance to load certs into the server
|
||||
* allowing it to verify incoming client certs
|
||||
*/
|
||||
if (vhost->tls.use_ssl) {
|
||||
if (lws_tls_server_vhost_backend_init(info, vhost, &wsi))
|
||||
return -1;
|
||||
|
||||
lws_tls_server_client_cert_verify_config(vhost);
|
||||
|
||||
if (vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
|
||||
vhost->tls.ssl_ctx, vhost, 0))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vhost->tls.use_ssl)
|
||||
lws_context_init_alpn(vhost);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_vhost *vh;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n;
|
||||
char buf[256];
|
||||
|
||||
(void)buf;
|
||||
|
||||
if (!LWS_SSL_ENABLED(wsi->vhost))
|
||||
return 0;
|
||||
|
||||
switch (lwsi_state(wsi)) {
|
||||
case LRS_SSL_INIT:
|
||||
|
||||
if (wsi->tls.ssl)
|
||||
lwsl_err("%s: leaking ssl\n", __func__);
|
||||
if (accept_fd == LWS_SOCK_INVALID)
|
||||
assert(0);
|
||||
if (context->simultaneous_ssl_restriction &&
|
||||
context->simultaneous_ssl >=
|
||||
context->simultaneous_ssl_restriction) {
|
||||
lwsl_notice("unable to deal with SSL connection\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_tls_server_new_nonblocking(wsi, accept_fd)) {
|
||||
if (accept_fd != LWS_SOCK_INVALID)
|
||||
compatible_close(accept_fd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (context->simultaneous_ssl_restriction &&
|
||||
++context->simultaneous_ssl ==
|
||||
context->simultaneous_ssl_restriction)
|
||||
/* that was the last allowed SSL connection */
|
||||
lws_gate_accepts(context, 0);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
context->updated = 1;
|
||||
#endif
|
||||
/*
|
||||
* we are not accepted yet, but we need to enter ourselves
|
||||
* as a live connection. That way we can retry when more
|
||||
* pieces come if we're not sorted yet
|
||||
*/
|
||||
lwsi_set_state(wsi, LRS_SSL_ACK_PENDING);
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
if (__insert_wsi_socket_into_fds(context, wsi)) {
|
||||
lwsl_err("%s: failed to insert into fds\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
|
||||
context->timeout_secs);
|
||||
|
||||
lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n");
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LRS_SSL_ACK_PENDING:
|
||||
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_err("%s: lws_change_pollfd failed\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
if (wsi->vhost->tls.allow_non_ssl_on_ssl_port) {
|
||||
|
||||
n = recv(wsi->desc.sockfd, (char *)pt->serv_buf,
|
||||
context->pt_serv_buf_size, MSG_PEEK);
|
||||
|
||||
/*
|
||||
* optionally allow non-SSL connect on SSL listening socket
|
||||
* This is disabled by default, if enabled it goes around any
|
||||
* SSL-level access control (eg, client-side certs) so leave
|
||||
* it disabled unless you know it's not a problem for you
|
||||
*/
|
||||
if (n >= 1 && pt->serv_buf[0] >= ' ') {
|
||||
/*
|
||||
* TLS content-type for Handshake is 0x16, and
|
||||
* for ChangeCipherSpec Record, it's 0x14
|
||||
*
|
||||
* A non-ssl session will start with the HTTP
|
||||
* method in ASCII. If we see it's not a legit
|
||||
* SSL handshake kill the SSL for this
|
||||
* connection and try to handle as a HTTP
|
||||
* connection upgrade directly.
|
||||
*/
|
||||
wsi->tls.use_ssl = 0;
|
||||
|
||||
lws_tls_server_abort_connection(wsi);
|
||||
/*
|
||||
* care... this creates wsi with no ssl
|
||||
* when ssl is enabled and normally
|
||||
* mandatory
|
||||
*/
|
||||
wsi->tls.ssl = NULL;
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS))
|
||||
wsi->tls.redirect_to_https = 1;
|
||||
lwsl_debug("accepted as non-ssl\n");
|
||||
goto accepted;
|
||||
}
|
||||
if (!n) {
|
||||
/*
|
||||
* connection is gone, fail out
|
||||
*/
|
||||
lwsl_debug("PEEKed 0\n");
|
||||
goto fail;
|
||||
}
|
||||
if (n < 0 && (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK)) {
|
||||
/*
|
||||
* well, we get no way to know ssl or not
|
||||
* so go around again waiting for something
|
||||
* to come and give us a hint, or timeout the
|
||||
* connection.
|
||||
*/
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
|
||||
lwsl_info("%s: change_pollfd failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lwsl_info("SSL_ERROR_WANT_READ\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* normal SSL connection processing path */
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->accept_start_us)
|
||||
wsi->accept_start_us = time_in_microseconds();
|
||||
#endif
|
||||
errno = 0;
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN, 1);
|
||||
n = lws_tls_server_accept(wsi);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_accept LRS_SSL_ACK_PENDING\n", n, n == 1);
|
||||
lwsl_info("SSL_accept says %d\n", n);
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_DONE:
|
||||
break;
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
|
||||
lwsl_info("SSL_accept failed socket %u: %d\n",
|
||||
wsi->desc.sockfd, n);
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
goto fail;
|
||||
|
||||
default: /* MORE_SERVICE */
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
lws_stats_atomic_bump(wsi->context, pt,
|
||||
LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY,
|
||||
time_in_microseconds() - wsi->accept_start_us);
|
||||
wsi->accept_start_us = time_in_microseconds();
|
||||
#endif
|
||||
|
||||
accepted:
|
||||
|
||||
/* adapt our vhost to match the SNI SSL_CTX that was chosen */
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
if (!vh->being_destroyed && wsi->tls.ssl &&
|
||||
vh->tls.ssl_ctx == lws_tls_ctx_from_wsi(wsi)) {
|
||||
lwsl_info("setting wsi to vh %s\n", vh->name);
|
||||
wsi->vhost = vh;
|
||||
break;
|
||||
}
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
/* OK, we are accepted... give him some time to negotiate */
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
context->timeout_secs);
|
||||
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
if (lws_tls_server_conn_alpn(wsi))
|
||||
goto fail;
|
||||
lwsl_debug("accepted new SSL conn\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,522 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 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 "core/private.h"
|
||||
|
||||
/*
|
||||
* fakes POLLIN on all tls guys with buffered rx
|
||||
*
|
||||
* returns nonzero if any tls guys had POLLIN faked
|
||||
*/
|
||||
|
||||
int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt)
|
||||
{
|
||||
struct lws *wsi, *wsi_next;
|
||||
int ret = 0;
|
||||
|
||||
wsi = pt->tls.pending_read_list;
|
||||
while (wsi && wsi->position_in_fds_table != LWS_NO_FDS_POS) {
|
||||
wsi_next = wsi->tls.pending_read_list_next;
|
||||
pt->fds[wsi->position_in_fds_table].revents |=
|
||||
pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
|
||||
ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN;
|
||||
|
||||
wsi = wsi_next;
|
||||
}
|
||||
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
void
|
||||
__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
if (!wsi->tls.pending_read_list_prev &&
|
||||
!wsi->tls.pending_read_list_next &&
|
||||
pt->tls.pending_read_list != wsi)
|
||||
/* we are not on the list */
|
||||
return;
|
||||
|
||||
/* point previous guy's next to our next */
|
||||
if (!wsi->tls.pending_read_list_prev)
|
||||
pt->tls.pending_read_list = wsi->tls.pending_read_list_next;
|
||||
else
|
||||
wsi->tls.pending_read_list_prev->tls.pending_read_list_next =
|
||||
wsi->tls.pending_read_list_next;
|
||||
|
||||
/* point next guy's previous to our previous */
|
||||
if (wsi->tls.pending_read_list_next)
|
||||
wsi->tls.pending_read_list_next->tls.pending_read_list_prev =
|
||||
wsi->tls.pending_read_list_prev;
|
||||
|
||||
wsi->tls.pending_read_list_prev = NULL;
|
||||
wsi->tls.pending_read_list_next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount)
|
||||
{
|
||||
nvs_handle nvh;
|
||||
size_t s;
|
||||
int n = 0;
|
||||
|
||||
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
|
||||
if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
*buf = lws_malloc(s + 1, "alloc_file");
|
||||
if (!*buf) {
|
||||
n = 2;
|
||||
goto bail;
|
||||
}
|
||||
if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) {
|
||||
lws_free(*buf);
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*amount = s;
|
||||
(*buf)[s] = '\0';
|
||||
|
||||
lwsl_notice("%s: nvs: read %s, %d bytes\n", __func__, filename, (int)s);
|
||||
|
||||
bail:
|
||||
nvs_close(nvh);
|
||||
|
||||
return n;
|
||||
}
|
||||
#else
|
||||
int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount)
|
||||
{
|
||||
FILE *f;
|
||||
size_t s;
|
||||
int n = 0;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_END) != 0) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
s = ftell(f);
|
||||
if (s == (size_t)-1) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*buf = lws_malloc(s, "alloc_file");
|
||||
if (!*buf) {
|
||||
n = 2;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (fread(*buf, s, 1, f) != 1) {
|
||||
lws_free(*buf);
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*amount = s;
|
||||
|
||||
bail:
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
return n;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
|
||||
const char *inbuf, lws_filepos_t inlen,
|
||||
uint8_t **buf, lws_filepos_t *amount)
|
||||
{
|
||||
const uint8_t *pem, *p, *end;
|
||||
uint8_t *q;
|
||||
lws_filepos_t len;
|
||||
int n;
|
||||
|
||||
if (filename) {
|
||||
n = alloc_file(context, filename, (uint8_t **)&pem, &len);
|
||||
if (n)
|
||||
return n;
|
||||
} else {
|
||||
pem = (const uint8_t *)inbuf;
|
||||
len = inlen;
|
||||
}
|
||||
|
||||
/* trim the first line */
|
||||
|
||||
p = pem;
|
||||
end = p + len;
|
||||
if (strncmp((char *)p, "-----", 5))
|
||||
goto bail;
|
||||
p += 5;
|
||||
while (p < end && *p != '\n' && *p != '-')
|
||||
p++;
|
||||
|
||||
if (*p != '-')
|
||||
goto bail;
|
||||
|
||||
while (p < end && *p != '\n')
|
||||
p++;
|
||||
|
||||
if (p >= end)
|
||||
goto bail;
|
||||
|
||||
p++;
|
||||
|
||||
/* trim the last line */
|
||||
|
||||
q = (uint8_t *)end - 2;
|
||||
|
||||
while (q > pem && *q != '\n')
|
||||
q--;
|
||||
|
||||
if (*q != '\n')
|
||||
goto bail;
|
||||
|
||||
*q = '\0';
|
||||
|
||||
*amount = lws_b64_decode_string((char *)p, (char *)pem,
|
||||
(int)(long long)len);
|
||||
*buf = (uint8_t *)pem;
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lws_free((uint8_t *)pem);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_cert_lifetime(struct lws_vhost *v)
|
||||
{
|
||||
union lws_tls_cert_info_results ir;
|
||||
time_t now = (time_t)lws_now_secs(), life = 0;
|
||||
struct lws_acme_cert_aging_args caa;
|
||||
int n;
|
||||
|
||||
if (v->tls.ssl_ctx && !v->tls.skipped_certs) {
|
||||
|
||||
if (now < 1464083026) /* May 2016 */
|
||||
/* our clock is wrong and we can't judge the certs */
|
||||
return -1;
|
||||
|
||||
n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO, &ir, 0);
|
||||
if (n)
|
||||
return 1;
|
||||
|
||||
life = (ir.time - now) / (24 * 3600);
|
||||
lwsl_notice(" vhost %s: cert expiry: %dd\n", v->name, (int)life);
|
||||
} else
|
||||
lwsl_notice(" vhost %s: no cert\n", v->name);
|
||||
|
||||
memset(&caa, 0, sizeof(caa));
|
||||
caa.vh = v;
|
||||
lws_broadcast(v->context, LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa,
|
||||
(size_t)(ssize_t)life);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
while (v) {
|
||||
if (lws_tls_check_cert_lifetime(v) < 0)
|
||||
return -1;
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
|
||||
static int
|
||||
lws_tls_extant(const char *name)
|
||||
{
|
||||
/* it exists if we can open it... */
|
||||
int fd = open(name, O_RDONLY), n;
|
||||
char buf[1];
|
||||
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
/* and we can read at least one byte out of it */
|
||||
n = read(fd, buf, 1);
|
||||
close(fd);
|
||||
|
||||
return n != 1;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Returns 0 if the filepath "name" exists and can be read from.
|
||||
*
|
||||
* In addition, if "name".upd exists, backup "name" to "name.old.1"
|
||||
* and rename "name".upd to "name" before reporting its existence.
|
||||
*
|
||||
* There are four situations and three results possible:
|
||||
*
|
||||
* 1) LWS_TLS_EXTANT_NO: There are no certs at all (we are waiting for them to
|
||||
* be provisioned). We also feel like this if we need privs we don't have
|
||||
* any more to look in the directory.
|
||||
*
|
||||
* 2) There are provisioned certs written (xxx.upd) and we still have root
|
||||
* privs... in this case we rename any existing cert to have a backup name
|
||||
* and move the upd cert into place with the correct name. This then becomes
|
||||
* situation 4 for the caller.
|
||||
*
|
||||
* 3) LWS_TLS_EXTANT_ALTERNATIVE: There are provisioned certs written (xxx.upd)
|
||||
* but we no longer have the privs needed to read or rename them. In this
|
||||
* case, indicate that the caller should use temp copies if any we do have
|
||||
* rights to access. This is normal after we have updated the cert.
|
||||
*
|
||||
* But if we dropped privs, we can't detect the provisioned xxx.upd cert +
|
||||
* key, because we can't see in the dir. So we have to upgrade NO to
|
||||
* ALTERNATIVE when we actually have the in-memory alternative.
|
||||
*
|
||||
* 4) LWS_TLS_EXTANT_YES: The certs are present with the correct name and we
|
||||
* have the rights to read them.
|
||||
*/
|
||||
enum lws_tls_extant
|
||||
lws_tls_use_any_upgrade_check_extant(const char *name)
|
||||
{
|
||||
#if !defined(LWS_PLAT_OPTEE)
|
||||
|
||||
int n;
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
char buf[256];
|
||||
|
||||
lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
|
||||
if (!lws_tls_extant(buf)) {
|
||||
/* ah there is an updated file... how about the desired file? */
|
||||
if (!lws_tls_extant(name)) {
|
||||
/* rename the desired file */
|
||||
for (n = 0; n < 50; n++) {
|
||||
lws_snprintf(buf, sizeof(buf) - 1,
|
||||
"%s.old.%d", name, n);
|
||||
if (!rename(name, buf))
|
||||
break;
|
||||
}
|
||||
if (n == 50) {
|
||||
lwsl_notice("unable to rename %s\n", name);
|
||||
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
}
|
||||
lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
|
||||
}
|
||||
/* desired file is out of the way, rename the updated file */
|
||||
if (rename(buf, name)) {
|
||||
lwsl_notice("unable to rename %s to %s\n", buf, name);
|
||||
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
if (lws_tls_extant(name))
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
#else
|
||||
nvs_handle nvh;
|
||||
size_t s = 8192;
|
||||
|
||||
if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
|
||||
lwsl_notice("%s: can't open nvs\n", __func__);
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
}
|
||||
|
||||
n = nvs_get_blob(nvh, name, NULL, &s);
|
||||
nvs_close(nvh);
|
||||
|
||||
if (n)
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
#endif
|
||||
#endif
|
||||
return LWS_TLS_EXTANT_YES;
|
||||
}
|
||||
|
||||
/*
|
||||
* LWS_TLS_EXTANT_NO : skip adding the cert
|
||||
* LWS_TLS_EXTANT_YES : use the cert and private key paths normally
|
||||
* LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss
|
||||
*/
|
||||
enum lws_tls_extant
|
||||
lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
|
||||
const char *private_key)
|
||||
{
|
||||
int n, m;
|
||||
|
||||
/*
|
||||
* The user code can choose to either pass the cert and
|
||||
* key filepaths using the info members like this, or it can
|
||||
* leave them NULL; force the vhost SSL_CTX init using the info
|
||||
* options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
|
||||
* set up the cert himself using the user callback
|
||||
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
|
||||
* happened just above and has the vhost SSL_CTX * in the user
|
||||
* parameter.
|
||||
*/
|
||||
|
||||
if (!cert || !private_key)
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
|
||||
n = lws_tls_use_any_upgrade_check_extant(cert);
|
||||
if (n == LWS_TLS_EXTANT_ALTERNATIVE)
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
m = lws_tls_use_any_upgrade_check_extant(private_key);
|
||||
if (m == LWS_TLS_EXTANT_ALTERNATIVE)
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
|
||||
if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) &&
|
||||
(vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) {
|
||||
lwsl_notice("Ignoring missing %s or %s\n", cert, private_key);
|
||||
vhost->tls.skipped_certs = 1;
|
||||
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* the cert + key exist
|
||||
*/
|
||||
|
||||
return LWS_TLS_EXTANT_YES;
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
/*
|
||||
* update the cert for every vhost using the given path
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_tls_cert_updated(struct lws_context *context, const char *certpath,
|
||||
const char *keypath,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t len_mem_privkey)
|
||||
{
|
||||
struct lws wsi;
|
||||
|
||||
wsi.context = context;
|
||||
|
||||
lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
|
||||
wsi.vhost = v;
|
||||
if (v->tls.alloc_cert_path && v->tls.key_path &&
|
||||
!strcmp(v->tls.alloc_cert_path, certpath) &&
|
||||
!strcmp(v->tls.key_path, keypath)) {
|
||||
lws_tls_server_certs_load(v, &wsi, certpath, keypath,
|
||||
mem_cert, len_mem_cert,
|
||||
mem_privkey, len_mem_privkey);
|
||||
|
||||
if (v->tls.skipped_certs)
|
||||
lwsl_notice("%s: vhost %s: cert unset\n",
|
||||
__func__, v->name);
|
||||
}
|
||||
} lws_end_foreach_ll(v, vhost_next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_gate_accepts(struct lws_context *context, int on)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
lwsl_notice("%s: on = %d\n", __func__, on);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
context->updated = 1;
|
||||
#endif
|
||||
|
||||
while (v) {
|
||||
if (v->tls.use_ssl && v->lserv_wsi &&
|
||||
lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
|
||||
(LWS_POLLIN) * on))
|
||||
lwsl_notice("Unable to set accept POLLIN %d\n", on);
|
||||
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
|
||||
|
||||
int
|
||||
lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
|
||||
{
|
||||
uint8_t *oos = os, *plen = NULL;
|
||||
|
||||
while (*comma && len > 1) {
|
||||
if (!plen && *comma == ' ') {
|
||||
comma++;
|
||||
continue;
|
||||
}
|
||||
if (!plen) {
|
||||
plen = os++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (*comma == ',') {
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
plen = NULL;
|
||||
comma++;
|
||||
} else {
|
||||
*os++ = *comma++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (plen)
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
|
||||
return lws_ptr_diff(os, oos);
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
diff --git a/thirdparty/libwebsockets/plat/lws-plat-win.c b/thirdparty/libwebsockets/plat/lws-plat-win.c
|
||||
index bd513b494..1850b6425 100644
|
||||
--- a/thirdparty/libwebsockets/plat/lws-plat-win.c
|
||||
+++ b/thirdparty/libwebsockets/plat/lws-plat-win.c
|
||||
@@ -641,9 +641,20 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
HANDLE ret;
|
||||
WCHAR buf[MAX_PATH];
|
||||
lws_fop_fd_t fop_fd;
|
||||
- LARGE_INTEGER llFileSize = {0};
|
||||
+ FILE_STANDARD_INFO fInfo = {0};
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, LWS_ARRAY_SIZE(buf));
|
||||
+
|
||||
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 // Windows 8 (minimum when UWP_ENABLED, but can be used in Windows builds)
|
||||
+ CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
|
||||
+ extParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
+
|
||||
+ if (((*flags) & 7) == _O_RDONLY) {
|
||||
+ ret = CreateFile2(buf, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extParams);
|
||||
+ } else {
|
||||
+ ret = CreateFile2(buf, GENERIC_WRITE, 0, CREATE_ALWAYS, &extParams);
|
||||
+ }
|
||||
+#else
|
||||
if (((*flags) & 7) == _O_RDONLY) {
|
||||
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
@@ -651,6 +662,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (ret == LWS_INVALID_FILE)
|
||||
goto bail;
|
||||
@@ -663,9 +675,9 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
fop_fd->fd = ret;
|
||||
fop_fd->filesystem_priv = NULL; /* we don't use it */
|
||||
fop_fd->flags = *flags;
|
||||
- fop_fd->len = GetFileSize(ret, NULL);
|
||||
- if(GetFileSizeEx(ret, &llFileSize))
|
||||
- fop_fd->len = llFileSize.QuadPart;
|
||||
+ fop_fd->len = 0;
|
||||
+ if(GetFileInformationByHandleEx(ret, FileStandardInfo, &fInfo, sizeof(fInfo)))
|
||||
+ fop_fd->len = fInfo.EndOfFile.QuadPart;
|
||||
|
||||
fop_fd->pos = 0;
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994
|
||||
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __P(x) x
|
||||
#define _DIAGASSERT(x) assert(x)
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(getopt,_getopt);
|
||||
#endif
|
||||
|
||||
|
||||
int opterr = 1, /* if error message should be printed */
|
||||
optind = 1, /* index into parent argv vector */
|
||||
optopt, /* character checked for validity */
|
||||
optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
|
||||
static char * _progname __P((char *));
|
||||
int getopt_internal __P((int, char * const *, const char *));
|
||||
|
||||
static char *
|
||||
_progname(nargv0)
|
||||
char * nargv0;
|
||||
{
|
||||
char * tmp;
|
||||
|
||||
_DIAGASSERT(nargv0 != NULL);
|
||||
|
||||
tmp = strrchr(nargv0, '/');
|
||||
if (tmp)
|
||||
tmp++;
|
||||
else
|
||||
tmp = nargv0;
|
||||
return(tmp);
|
||||
}
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt(nargc, nargv, ostr)
|
||||
int nargc;
|
||||
char * const nargv[];
|
||||
const char *ostr;
|
||||
{
|
||||
static char *__progname = 0;
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
__progname = __progname?__progname:_progname(*nargv);
|
||||
|
||||
_DIAGASSERT(nargv != NULL);
|
||||
_DIAGASSERT(ostr != NULL);
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-' /* found "--" */
|
||||
&& place[1] == '\0') {
|
||||
++optind;
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' ||
|
||||
!(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int)'-')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void)fprintf(stderr,
|
||||
"%s: illegal option -- %c\n", __progname, optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
}
|
||||
else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if (*ostr == ':')
|
||||
return (BADARG);
|
||||
if (opterr)
|
||||
(void)fprintf(stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
__progname, optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* dump back option letter */
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#ifndef __GETOPT_H__
|
||||
#define __GETOPT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int opterr; /* if error message should be printed */
|
||||
extern int optind; /* index into parent argv vector */
|
||||
extern int optopt; /* character checked for validity */
|
||||
extern int optreset; /* reset getopt */
|
||||
extern char *optarg; /* argument associated with option */
|
||||
|
||||
struct option
|
||||
{
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
int getopt(int, char**, char*);
|
||||
int getopt_long(int, char**, char*, struct option*, int*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GETOPT_H__ */
|
|
@ -1,240 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994, 1996
|
||||
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "getopt.h"
|
||||
|
||||
#define lws_ptr_diff(head, tail) \
|
||||
((int)((char *)(head) - (char *)(tail)))
|
||||
|
||||
extern int opterr; /* if error message should be printed */
|
||||
extern int optind; /* index into parent argv vector */
|
||||
extern int optopt; /* character checked for validity */
|
||||
extern int optreset; /* reset getopt */
|
||||
extern char *optarg; /* argument associated with option */
|
||||
|
||||
#define __P(x) x
|
||||
#define _DIAGASSERT(x) assert(x)
|
||||
|
||||
static char * __progname __P((char *));
|
||||
int getopt_internal __P((int, char * const *, const char *));
|
||||
|
||||
static char *
|
||||
__progname(nargv0)
|
||||
char * nargv0;
|
||||
{
|
||||
char * tmp;
|
||||
|
||||
_DIAGASSERT(nargv0 != NULL);
|
||||
|
||||
tmp = strrchr(nargv0, '/');
|
||||
if (tmp)
|
||||
tmp++;
|
||||
else
|
||||
tmp = nargv0;
|
||||
return(tmp);
|
||||
}
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_internal(nargc, nargv, ostr)
|
||||
int nargc;
|
||||
char * const *nargv;
|
||||
const char *ostr;
|
||||
{
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
|
||||
_DIAGASSERT(nargv != NULL);
|
||||
_DIAGASSERT(ostr != NULL);
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-') { /* found "--" */
|
||||
/* ++optind; */
|
||||
place = EMSG;
|
||||
return (-2);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' ||
|
||||
!(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int)'-')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void)fprintf(stderr,
|
||||
"%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
} else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if ((opterr) && (*ostr != ':'))
|
||||
(void)fprintf(stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
__progname(nargv[0]), optopt);
|
||||
return (BADARG);
|
||||
} else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* dump back option letter */
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt2(nargc, nargv, ostr)
|
||||
int nargc;
|
||||
char * const *nargv;
|
||||
const char *ostr;
|
||||
{
|
||||
int retval;
|
||||
|
||||
if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
|
||||
retval = -1;
|
||||
++optind;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* getopt_long --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_long(nargc, nargv, options, long_options, index)
|
||||
int nargc;
|
||||
char ** nargv;
|
||||
char * options;
|
||||
struct option * long_options;
|
||||
int * index;
|
||||
{
|
||||
int retval;
|
||||
|
||||
_DIAGASSERT(nargv != NULL);
|
||||
_DIAGASSERT(options != NULL);
|
||||
_DIAGASSERT(long_options != NULL);
|
||||
/* index may be NULL */
|
||||
|
||||
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
|
||||
char *current_argv = nargv[optind++] + 2, *has_equal;
|
||||
int i, current_argv_len, match = -1;
|
||||
|
||||
if (*current_argv == '\0') {
|
||||
return(-1);
|
||||
}
|
||||
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||
current_argv_len = lws_ptr_diff(has_equal, current_argv);
|
||||
has_equal++;
|
||||
} else
|
||||
current_argv_len = (int)strlen(current_argv);
|
||||
|
||||
for (i = 0; long_options[i].name; i++) {
|
||||
if (strncmp(current_argv, long_options[i].name, current_argv_len))
|
||||
continue;
|
||||
|
||||
if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
if (match == -1)
|
||||
match = i;
|
||||
}
|
||||
if (match != -1) {
|
||||
if (long_options[match].has_arg == required_argument ||
|
||||
long_options[match].has_arg == optional_argument) {
|
||||
if (has_equal)
|
||||
optarg = has_equal;
|
||||
else
|
||||
optarg = nargv[optind++];
|
||||
}
|
||||
if ((long_options[match].has_arg == required_argument)
|
||||
&& (optarg == NULL)) {
|
||||
/*
|
||||
* Missing argument, leading :
|
||||
* indicates no error should be generated
|
||||
*/
|
||||
if ((opterr) && (*options != ':'))
|
||||
(void)fprintf(stderr,
|
||||
"%s: option requires an argument -- %s\n",
|
||||
__progname(nargv[0]), current_argv);
|
||||
return (BADARG);
|
||||
}
|
||||
} else { /* No matching argument */
|
||||
if ((opterr) && (*options != ':'))
|
||||
(void)fprintf(stderr,
|
||||
"%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
|
||||
return (BADCH);
|
||||
}
|
||||
if (long_options[match].flag) {
|
||||
*long_options[match].flag = long_options[match].val;
|
||||
retval = 0;
|
||||
} else
|
||||
retval = long_options[match].val;
|
||||
if (index)
|
||||
*index = match;
|
||||
}
|
||||
return(retval);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
#include <time.h>
|
||||
#include <windows.h> //I've omitted context line
|
||||
|
||||
#include "gettimeofday.h"
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
FILETIME ft;
|
||||
unsigned __int64 tmpres = 0;
|
||||
static int tzflag;
|
||||
|
||||
if (NULL != tv) {
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
tmpres |= ft.dwHighDateTime;
|
||||
tmpres <<= 32;
|
||||
tmpres |= ft.dwLowDateTime;
|
||||
|
||||
/*converting file time to unix epoch*/
|
||||
tmpres /= 10; /*convert into microseconds*/
|
||||
tmpres -= DELTA_EPOCH_IN_MICROSECS;
|
||||
tv->tv_sec = (long)(tmpres / 1000000UL);
|
||||
tv->tv_usec = (long)(tmpres % 1000000UL);
|
||||
}
|
||||
|
||||
if (NULL != tz) {
|
||||
if (!tzflag) {
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef _GET_TIME_OF_DAY_H
|
||||
#define _GET_TIME_OF_DAY_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
||||
#else
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
||||
#endif
|
||||
|
||||
#ifdef LWS_MINGW_SUPPORT
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifndef _TIMEZONE_DEFINED
|
||||
struct timezone
|
||||
{
|
||||
int tz_minuteswest; /* minutes W of Greenwich */
|
||||
int tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue