Compare commits
28 Commits
f6480ba8ad
...
b6b31818aa
Author | SHA1 | Date | |
---|---|---|---|
b6b31818aa | |||
681f65a6c4 | |||
540aab40d4 | |||
79c20a74ea | |||
1617790e48 | |||
5e422227ab | |||
273982e7d3 | |||
212731101e | |||
b6d77a7910 | |||
c653ed5b4b | |||
6ec43d60ed | |||
e6f2d8041b | |||
34bd74c67f | |||
19ab3637cf | |||
790c165268 | |||
cb097b3ce5 | |||
73c73ef1f5 | |||
29607a6d46 | |||
54a5b66436 | |||
d260646f29 | |||
36e7081920 | |||
63c9757a50 | |||
0f4bbb87f7 | |||
65ff5fb439 | |||
85c8aeaad8 | |||
39660fae32 | |||
18a4b7f72b | |||
2911d1c411 |
373
LICENSE
Normal file
373
LICENSE
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
@ -65,15 +65,15 @@ Compile software:
|
|||||||
lutin -C -P enet-test?build?run
|
lutin -C -P enet-test?build?run
|
||||||
|
|
||||||
|
|
||||||
License (APACHE v2.0)
|
License (MPL v2.0)
|
||||||
=====================
|
=====================
|
||||||
Copyright enet Edouard DUPIN
|
Copyright enet Edouard DUPIN
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Mozilla Public License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
https://www.mozilla.org/MPL/2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@ -38,16 +38,16 @@ Are there any licensing restrictions? {#enet_mainpage_license_restric
|
|||||||
ENET is **FREE software** and _all sub-library are FREE and staticly linkable !!!_
|
ENET is **FREE software** and _all sub-library are FREE and staticly linkable !!!_
|
||||||
|
|
||||||
|
|
||||||
License (APACHE-2.0) {#enet_mainpage_license}
|
License (MPL v2.0) {#enet_mainpage_license}
|
||||||
====================
|
==================
|
||||||
|
|
||||||
Copyright ENET Edouard DUPIN
|
Copyright ENET Edouard DUPIN
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Mozilla Public License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
<http://www.apache.org/licenses/LICENSE-2.0>
|
<https://www.mozilla.org/MPL/2.0>
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
#include <enet/Ftp.hpp>
|
#include <enet/Ftp.hpp>
|
||||||
#include <cstring>
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
373
enet/Http.cpp
373
enet/Http.cpp
@ -1,24 +1,29 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
#include <enet/Http.hpp>
|
#include <enet/Http.hpp>
|
||||||
#include <map>
|
#include <etk/Map.hpp>
|
||||||
|
#include <etk/Stream.hpp>
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
#include <cstring>
|
#include <enet/TcpClient.hpp>
|
||||||
|
#include <enet/pourcentEncoding.hpp>
|
||||||
|
extern "C" {
|
||||||
|
#include <string.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string escapeChar(const std::string& _value) {
|
static etk::String escapeChar(const etk::String& _value) {
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
static std::string unEscapeChar(const std::string& _value) {
|
static etk::String unEscapeChar(const etk::String& _value) {
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
static std::string removeStartAndStopSpace(const std::string& _value) {
|
static etk::String removeStartAndStopSpace(const etk::String& _value) {
|
||||||
std::string out;
|
etk::String out;
|
||||||
out.reserve(_value.size());
|
out.reserve(_value.size());
|
||||||
bool findSpace = false;
|
bool findSpace = false;
|
||||||
for (auto &it : _value) {
|
for (auto &it : _value) {
|
||||||
@ -36,64 +41,71 @@ static std::string removeStartAndStopSpace(const std::string& _value) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<enet::HTTPAnswerCode, std::string> protocolName = {
|
static const etk::Map<enet::HTTPAnswerCode, etk::String>& getProtocolName() {
|
||||||
{enet::HTTPAnswerCode::c100_continue, "Continue"},
|
static etk::Map<enet::HTTPAnswerCode, etk::String> protocolName;
|
||||||
{enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols"},
|
static bool isInit = false;
|
||||||
{enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint"},
|
if (isInit == true) {
|
||||||
{enet::HTTPAnswerCode::c200_ok, "OK"},
|
return protocolName;
|
||||||
{enet::HTTPAnswerCode::c201_created, "Created"},
|
}
|
||||||
{enet::HTTPAnswerCode::c202_accepted, "Accepted"},
|
isInit = true;
|
||||||
{enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information"},
|
protocolName.add(enet::HTTPAnswerCode::c100_continue, "Continue");
|
||||||
{enet::HTTPAnswerCode::c204_noContent, "No Content"},
|
protocolName.add(enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols");
|
||||||
{enet::HTTPAnswerCode::c205_resetContent, "Reset Content"},
|
protocolName.add(enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint");
|
||||||
{enet::HTTPAnswerCode::c206_partialContent, "Partial Content"},
|
protocolName.add(enet::HTTPAnswerCode::c200_ok, "OK");
|
||||||
{enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices"},
|
protocolName.add(enet::HTTPAnswerCode::c201_created, "Created");
|
||||||
{enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently"},
|
protocolName.add(enet::HTTPAnswerCode::c202_accepted, "Accepted");
|
||||||
{enet::HTTPAnswerCode::c302_found, "Found"},
|
protocolName.add(enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information");
|
||||||
{enet::HTTPAnswerCode::c303_seeOther, "See Other"},
|
protocolName.add(enet::HTTPAnswerCode::c204_noContent, "No Content");
|
||||||
{enet::HTTPAnswerCode::c304_notModified, "Not Modified"},
|
protocolName.add(enet::HTTPAnswerCode::c205_resetContent, "Reset Content");
|
||||||
{enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy"},
|
protocolName.add(enet::HTTPAnswerCode::c206_partialContent, "Partial Content");
|
||||||
{enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect"},
|
protocolName.add(enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices");
|
||||||
{enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete"},
|
protocolName.add(enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently");
|
||||||
{enet::HTTPAnswerCode::c400_badRequest, "Bad Request"},
|
protocolName.add(enet::HTTPAnswerCode::c302_found, "Found");
|
||||||
{enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized"},
|
protocolName.add(enet::HTTPAnswerCode::c303_seeOther, "See Other");
|
||||||
{enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required"},
|
protocolName.add(enet::HTTPAnswerCode::c304_notModified, "Not Modified");
|
||||||
{enet::HTTPAnswerCode::c403_forbidden, "Forbidden"},
|
protocolName.add(enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy");
|
||||||
{enet::HTTPAnswerCode::c404_notFound, "Not Found"},
|
protocolName.add(enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect");
|
||||||
{enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed"},
|
protocolName.add(enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete");
|
||||||
{enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable"},
|
protocolName.add(enet::HTTPAnswerCode::c400_badRequest, "Bad Request");
|
||||||
{enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required"},
|
protocolName.add(enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized");
|
||||||
{enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout"},
|
protocolName.add(enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required");
|
||||||
{enet::HTTPAnswerCode::c409_conflict, "Conflict"},
|
protocolName.add(enet::HTTPAnswerCode::c403_forbidden, "Forbidden");
|
||||||
{enet::HTTPAnswerCode::c410_gone, "Gone"},
|
protocolName.add(enet::HTTPAnswerCode::c404_notFound, "Not Found");
|
||||||
{enet::HTTPAnswerCode::c411_lengthRequired, "Length Required"},
|
protocolName.add(enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed");
|
||||||
{enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed"},
|
protocolName.add(enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable");
|
||||||
{enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large"},
|
protocolName.add(enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required");
|
||||||
{enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long"},
|
protocolName.add(enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout");
|
||||||
{enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type"},
|
protocolName.add(enet::HTTPAnswerCode::c409_conflict, "Conflict");
|
||||||
{enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable"},
|
protocolName.add(enet::HTTPAnswerCode::c410_gone, "Gone");
|
||||||
{enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed"},
|
protocolName.add(enet::HTTPAnswerCode::c411_lengthRequired, "Length Required");
|
||||||
{enet::HTTPAnswerCode::c500_internalServerError, "Internal Server Error"},
|
protocolName.add(enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed");
|
||||||
{enet::HTTPAnswerCode::c501_notImplemented, "Not Implemented"},
|
protocolName.add(enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large");
|
||||||
{enet::HTTPAnswerCode::c502_badGateway, "Bad Gateway"},
|
protocolName.add(enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long");
|
||||||
{enet::HTTPAnswerCode::c503_serviceUnavailable, "Service Unavailable"},
|
protocolName.add(enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type");
|
||||||
{enet::HTTPAnswerCode::c504_gatewayTimeout, "Gateway Timeout"},
|
protocolName.add(enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable");
|
||||||
{enet::HTTPAnswerCode::c505_httpVersionNotSupported, "HTTP Version Not Supported"},
|
protocolName.add(enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed");
|
||||||
{enet::HTTPAnswerCode::c511_networkAuthenticationRequired, "Network Authentication Required"}
|
protocolName.add(enet::HTTPAnswerCode::c500_internalServerError, "Internal Server Error");
|
||||||
|
protocolName.add(enet::HTTPAnswerCode::c501_notImplemented, "Not Implemented");
|
||||||
|
protocolName.add(enet::HTTPAnswerCode::c502_badGateway, "Bad Gateway");
|
||||||
|
protocolName.add(enet::HTTPAnswerCode::c503_serviceUnavailable, "Service Unavailable");
|
||||||
|
protocolName.add(enet::HTTPAnswerCode::c504_gatewayTimeout, "Gateway Timeout");
|
||||||
|
protocolName.add(enet::HTTPAnswerCode::c505_httpVersionNotSupported, "HTTP Version Not Supported");
|
||||||
|
protocolName.add(enet::HTTPAnswerCode::c511_networkAuthenticationRequired, "Network Authentication Required");
|
||||||
|
return protocolName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static std::map<int32_t, std::string> getErrorList() {
|
static etk::Map<int32_t, etk::String> getErrorList() {
|
||||||
static std::map<int32_t, std::string> g_list;
|
static etk::Map<int32_t, etk::String> g_list;
|
||||||
return g_list;
|
return g_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
enet::Http::Http(enet::Tcp _connection, bool _isServer) :
|
enet::Http::Http(enet::Tcp _connection, bool _isServer) :
|
||||||
m_isServer(_isServer),
|
m_isServer(_isServer),
|
||||||
m_connection(std::move(_connection)),
|
m_connection(etk::move(_connection)),
|
||||||
m_headerIsSend(false),
|
m_headerIsSend(false),
|
||||||
m_thread(nullptr),
|
m_thread(null),
|
||||||
m_threadRunning(false) {
|
m_threadRunning(false) {
|
||||||
//setSendHeaderProperties("User-Agent", "e-net (ewol network interface)");
|
//setSendHeaderProperties("User-Agent", "e-net (ewol network interface)");
|
||||||
/*
|
/*
|
||||||
@ -116,16 +128,18 @@ void enet::Http::threadCallback() {
|
|||||||
// READ section data:
|
// READ section data:
|
||||||
if (m_headerIsSend == false) {
|
if (m_headerIsSend == false) {
|
||||||
getHeader();
|
getHeader();
|
||||||
m_headerIsSend = true;
|
if (m_headerIsSend == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (m_observerRaw != nullptr) {
|
if (m_observerRaw != null) {
|
||||||
m_observerRaw(m_connection);
|
m_observerRaw(m_connection);
|
||||||
} else {
|
} else {
|
||||||
m_temporaryBuffer.resize(67000);
|
m_temporaryBuffer.resize(67000);
|
||||||
int32_t len = m_connection.read(&m_temporaryBuffer[0], m_temporaryBuffer.size());
|
int32_t len = m_connection.read(&m_temporaryBuffer[0], m_temporaryBuffer.size());
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
ENET_INFO("Call client with datas ...");
|
ENET_INFO("Call client with datas ...");
|
||||||
if (m_observer != nullptr) {
|
if (m_observer != null) {
|
||||||
m_observer(m_temporaryBuffer);
|
m_observer(m_temporaryBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,19 +149,28 @@ void enet::Http::threadCallback() {
|
|||||||
ENET_DEBUG("End of thread HTTP");
|
ENET_DEBUG("End of thread HTTP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enet::Http::redirectTo(const etk::String& _addressRedirect, bool _inThreadStop) {
|
||||||
|
if (m_isServer == true) {
|
||||||
|
ENET_ERROR("Request a redirect in Server mode ==> not authorised");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stop(_inThreadStop);
|
||||||
|
m_headerIsSend = false;
|
||||||
|
m_connection = etk::move(connectTcpClient(_addressRedirect, 5, echrono::seconds(1)));
|
||||||
|
}
|
||||||
|
|
||||||
void enet::Http::start() {
|
void enet::Http::start() {
|
||||||
ENET_DEBUG("connect [START]");
|
ENET_DEBUG("connect [START]");
|
||||||
m_threadRunning = true;
|
m_threadRunning = true;
|
||||||
m_thread = new std::thread([&](void *){ this->threadCallback();}, nullptr);
|
m_thread = ETK_NEW(ethread::Thread, [&](){ threadCallback();});
|
||||||
if (m_thread == nullptr) {
|
if (m_thread == null) {
|
||||||
m_threadRunning = false;
|
m_threadRunning = false;
|
||||||
ENET_ERROR("creating callback thread!");
|
ENET_ERROR("creating callback thread!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while ( m_threadRunning == true
|
while ( m_threadRunning == true
|
||||||
&& m_connection.getConnectionStatus() != enet::Tcp::status::link) {
|
&& m_connection.getConnectionStatus() != enet::Tcp::status::link) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
ethread::sleepMilliSeconds((50));
|
||||||
}
|
}
|
||||||
//ethread::setPriority(*m_receiveThread, -6);
|
//ethread::setPriority(*m_receiveThread, -6);
|
||||||
ENET_DEBUG("connect [STOP]");
|
ENET_DEBUG("connect [STOP]");
|
||||||
@ -166,21 +189,23 @@ void enet::Http::stop(bool _inThreadStop){
|
|||||||
m_connection.unlink();
|
m_connection.unlink();
|
||||||
}
|
}
|
||||||
if (_inThreadStop == false) {
|
if (_inThreadStop == false) {
|
||||||
if (m_thread != nullptr) {
|
if (m_thread != null) {
|
||||||
|
ENET_DEBUG("wait join Thread ...");
|
||||||
m_thread->join();
|
m_thread->join();
|
||||||
delete m_thread;
|
ENET_DEBUG("wait join Thread (done)");
|
||||||
m_thread = nullptr;
|
ETK_DELETE(ethread::Thread, m_thread);
|
||||||
|
m_thread = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ENET_DEBUG("disconnect [STOP]");
|
ENET_DEBUG("disconnect [STOP]");
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
|
void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
|
||||||
std::string out;
|
etk::String out;
|
||||||
out = "HTTP/1.1 ";
|
out = "HTTP/1.1 ";
|
||||||
out += etk::to_string(int32_t(_value));
|
out += etk::toString(int32_t(_value));
|
||||||
auto it = protocolName.find(_value);
|
auto it = getProtocolName().find(_value);
|
||||||
if (it == protocolName.end() ) {
|
if (it == getProtocolName().end() ) {
|
||||||
out += " ???";
|
out += " ???";
|
||||||
} else {
|
} else {
|
||||||
out += " " + it->second;
|
out += " " + it->second;
|
||||||
@ -192,10 +217,10 @@ void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
|
|||||||
*/
|
*/
|
||||||
namespace etk {
|
namespace etk {
|
||||||
template <>
|
template <>
|
||||||
bool from_string<enum enet::HTTPAnswerCode>(enum enet::HTTPAnswerCode& _variableRet, const std::string& _value) {
|
bool from_string<enum enet::HTTPAnswerCode>(enum enet::HTTPAnswerCode& _variableRet, const etk::String& _value) {
|
||||||
_variableRet = enet::HTTPAnswerCode::c000_unknow;
|
_variableRet = enet::HTTPAnswerCode::c000_unknow;
|
||||||
for (auto &it : protocolName) {
|
for (auto &it : getProtocolName()) {
|
||||||
if (etk::to_string(int32_t(it.first)) == _value) {
|
if (etk::toString(int32_t(it.first)) == _value) {
|
||||||
_variableRet = it.first;
|
_variableRet = it.first;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -203,11 +228,11 @@ namespace etk {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
std::string to_string<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
|
etk::String toString<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
|
||||||
return etk::to_string(int32_t(_value));
|
return etk::toString(int32_t(_value));
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const std::string& _value) {
|
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const etk::String& _value) {
|
||||||
_variableRet = enet::HTTPReqType::HTTP_GET;
|
_variableRet = enet::HTTPReqType::HTTP_GET;
|
||||||
if (_value == "GET") {
|
if (_value == "GET") {
|
||||||
_variableRet = enet::HTTPReqType::HTTP_GET;
|
_variableRet = enet::HTTPReqType::HTTP_GET;
|
||||||
@ -224,22 +249,26 @@ namespace etk {
|
|||||||
} else if (_value == "DELETE") {
|
} else if (_value == "DELETE") {
|
||||||
_variableRet = enet::HTTPReqType::HTTP_DELETE;
|
_variableRet = enet::HTTPReqType::HTTP_DELETE;
|
||||||
return true;
|
return true;
|
||||||
|
} else if (_value == "OPTIONS") {
|
||||||
|
_variableRet = enet::HTTPReqType::HTTP_OPTIONS;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
std::string to_string<enum enet::HTTPReqType>(const enum enet::HTTPReqType& _value) {
|
etk::String toString<enum enet::HTTPReqType>(const enum enet::HTTPReqType& _value) {
|
||||||
switch (_value) {
|
switch (_value) {
|
||||||
case enet::HTTPReqType::HTTP_GET: return "GET";
|
case enet::HTTPReqType::HTTP_GET: return "GET";
|
||||||
case enet::HTTPReqType::HTTP_HEAD: return "HEAD";
|
case enet::HTTPReqType::HTTP_HEAD: return "HEAD";
|
||||||
case enet::HTTPReqType::HTTP_POST: return "POST";
|
case enet::HTTPReqType::HTTP_POST: return "POST";
|
||||||
case enet::HTTPReqType::HTTP_PUT: return "PUT";
|
case enet::HTTPReqType::HTTP_PUT: return "PUT";
|
||||||
case enet::HTTPReqType::HTTP_DELETE: return "DELETE";
|
case enet::HTTPReqType::HTTP_DELETE: return "DELETE";
|
||||||
|
case enet::HTTPReqType::HTTP_OPTIONS: return "OPTIONS";
|
||||||
}
|
}
|
||||||
return "UNKNOW";
|
return "UNKNOW";
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
bool from_string<enum enet::HTTPProtocol>(enum enet::HTTPProtocol& _variableRet, const std::string& _value) {
|
bool from_string<enum enet::HTTPProtocol>(enum enet::HTTPProtocol& _variableRet, const etk::String& _value) {
|
||||||
_variableRet = enet::HTTPProtocol::http_0_1;
|
_variableRet = enet::HTTPProtocol::http_0_1;
|
||||||
if (_value == "HTTP/0.1") { _variableRet = enet::HTTPProtocol::http_0_1; return true; }
|
if (_value == "HTTP/0.1") { _variableRet = enet::HTTPProtocol::http_0_1; return true; }
|
||||||
if (_value == "HTTP/0.2") { _variableRet = enet::HTTPProtocol::http_0_2; return true; }
|
if (_value == "HTTP/0.2") { _variableRet = enet::HTTPProtocol::http_0_2; return true; }
|
||||||
@ -287,7 +316,7 @@ namespace etk {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
std::string to_string<enum enet::HTTPProtocol>(const enum enet::HTTPProtocol& _value) {
|
etk::String toString<enum enet::HTTPProtocol>(const enum enet::HTTPProtocol& _value) {
|
||||||
switch (_value) {
|
switch (_value) {
|
||||||
case enet::HTTPProtocol::http_0_1: return "HTTP/0.1";
|
case enet::HTTPProtocol::http_0_1: return "HTTP/0.1";
|
||||||
case enet::HTTPProtocol::http_0_2: return "HTTP/0.2";
|
case enet::HTTPProtocol::http_0_2: return "HTTP/0.2";
|
||||||
@ -340,31 +369,43 @@ namespace etk {
|
|||||||
|
|
||||||
void enet::Http::setRequestHeader(const enet::HttpRequest& _req) {
|
void enet::Http::setRequestHeader(const enet::HttpRequest& _req) {
|
||||||
m_requestHeader = _req;
|
m_requestHeader = _req;
|
||||||
if (m_requestHeader.getKey("User-Agent") == "") {
|
if (m_isServer == true) {
|
||||||
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
|
if (m_requestHeader.getKey("Server") == "") {
|
||||||
|
m_requestHeader.setKey("Server", "e-net (ewol network interface)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_requestHeader.getKey("User-Agent") == "") {
|
||||||
|
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::string value = m_requestHeader.generate();
|
etk::String value = m_requestHeader.generate();
|
||||||
write(value, false);
|
write(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::Http::setAnswerHeader(const enet::HttpAnswer& _req) {
|
void enet::Http::setAnswerHeader(const enet::HttpAnswer& _req) {
|
||||||
m_answerHeader = _req;
|
m_answerHeader = _req;
|
||||||
if (m_requestHeader.getKey("User-Agent") == "") {
|
if (m_isServer == true) {
|
||||||
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
|
if (m_requestHeader.getKey("Server") == "") {
|
||||||
|
m_requestHeader.setKey("Server", "e-net (ewol network interface)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_requestHeader.getKey("User-Agent") == "") {
|
||||||
|
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::string value = m_answerHeader.generate();
|
etk::String value = m_answerHeader.generate();
|
||||||
write(value, false);
|
write(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::Http::getHeader() {
|
void enet::Http::getHeader() {
|
||||||
ENET_VERBOSE("Read HTTP Header [START]");
|
ENET_VERBOSE("Read HTTP Header [START]");
|
||||||
bool headerEnded = false;
|
bool headerEnded = false;
|
||||||
std::string header;
|
etk::String header;
|
||||||
while (m_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
while (m_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
||||||
char type;
|
char type = '?';
|
||||||
int32_t len = m_connection.read(&type, 1);
|
int32_t len = m_connection.read(&type, 1);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(1));
|
ethread::sleepMilliSeconds(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
header += type;
|
header += type;
|
||||||
@ -394,7 +435,7 @@ void enet::Http::getHeader() {
|
|||||||
ENET_VERBOSE("Read HTTP Header [STOP] : '" << header << "'");
|
ENET_VERBOSE("Read HTTP Header [STOP] : '" << header << "'");
|
||||||
m_headerIsSend = true;
|
m_headerIsSend = true;
|
||||||
// parse header :
|
// parse header :
|
||||||
std::vector<std::string> list = etk::split(header, '\n');
|
etk::Vector<etk::String> list = etk::split(header, '\n');
|
||||||
for (auto &it : list) {
|
for (auto &it : list) {
|
||||||
if ( it.size()>0
|
if ( it.size()>0
|
||||||
&& it[it.size()-1] == '\r') {
|
&& it[it.size()-1] == '\r') {
|
||||||
@ -402,7 +443,7 @@ void enet::Http::getHeader() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//parse first element:
|
//parse first element:
|
||||||
std::vector<std::string> listLineOne = etk::split(list[0], ' ');
|
etk::Vector<etk::String> listLineOne = etk::split(list[0], ' ');
|
||||||
if (listLineOne.size() < 2) {
|
if (listLineOne.size() < 2) {
|
||||||
ENET_ERROR("can not parse answear : " << listLineOne);
|
ENET_ERROR("can not parse answear : " << listLineOne);
|
||||||
// answer bad request and close connection ...
|
// answer bad request and close connection ...
|
||||||
@ -414,7 +455,8 @@ void enet::Http::getHeader() {
|
|||||||
|| listLineOne[0] == "POST"
|
|| listLineOne[0] == "POST"
|
||||||
|| listLineOne[0] == "HEAD"
|
|| listLineOne[0] == "HEAD"
|
||||||
|| listLineOne[0] == "DELETE"
|
|| listLineOne[0] == "DELETE"
|
||||||
|| listLineOne[0] == "PUT" ) ) {
|
|| listLineOne[0] == "PUT"
|
||||||
|
|| listLineOne[0] == "OPTIONS" ) ) {
|
||||||
// HTTP CALL
|
// HTTP CALL
|
||||||
if (m_isServer == false) {
|
if (m_isServer == false) {
|
||||||
// can not have call in client mode
|
// can not have call in client mode
|
||||||
@ -430,7 +472,14 @@ void enet::Http::getHeader() {
|
|||||||
etk::from_string(valueType, listLineOne[0]);
|
etk::from_string(valueType, listLineOne[0]);
|
||||||
m_requestHeader.setType(valueType);
|
m_requestHeader.setType(valueType);
|
||||||
// get URI:
|
// get URI:
|
||||||
m_requestHeader.setUri(listLineOne[1]);
|
etk::String basicUri = listLineOne[1];
|
||||||
|
size_t pos = basicUri.find('?');
|
||||||
|
if (pos == etk::String::npos) {
|
||||||
|
m_requestHeader.setUri(listLineOne[1]);
|
||||||
|
} else {
|
||||||
|
m_requestHeader.setUri(basicUri.extract(0, pos));
|
||||||
|
m_requestHeader.setQuery(pourcentUriDecode(basicUri.extract(pos+1)));
|
||||||
|
}
|
||||||
// Get http version:
|
// Get http version:
|
||||||
enum enet::HTTPProtocol valueProtocol;
|
enum enet::HTTPProtocol valueProtocol;
|
||||||
etk::from_string(valueProtocol, listLineOne[2]);
|
etk::from_string(valueProtocol, listLineOne[2]);
|
||||||
@ -457,7 +506,7 @@ void enet::Http::getHeader() {
|
|||||||
m_answerHeader.setErrorCode(valueErrorCode);
|
m_answerHeader.setErrorCode(valueErrorCode);
|
||||||
|
|
||||||
// get comment:
|
// get comment:
|
||||||
std::string comment;
|
etk::String comment;
|
||||||
for (size_t iii=2; iii<listLineOne.size(); ++iii) {
|
for (size_t iii=2; iii<listLineOne.size(); ++iii) {
|
||||||
if (comment.size() != 0) {
|
if (comment.size() != 0) {
|
||||||
comment += " ";
|
comment += " ";
|
||||||
@ -476,13 +525,13 @@ void enet::Http::getHeader() {
|
|||||||
}
|
}
|
||||||
for (size_t iii=1; iii<list.size(); ++iii) {
|
for (size_t iii=1; iii<list.size(); ++iii) {
|
||||||
size_t found = list[iii].find(":");
|
size_t found = list[iii].find(":");
|
||||||
if (found == std::string::npos) {
|
if (found == etk::String::npos) {
|
||||||
// nothing
|
// nothing
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::string key = unEscapeChar(std::string(list[iii], 0, found));
|
etk::String key = unEscapeChar(etk::String(list[iii], 0, found));
|
||||||
key = removeStartAndStopSpace(key);
|
key = removeStartAndStopSpace(key);
|
||||||
std::string value = unEscapeChar(std::string(list[iii], found+2));
|
etk::String value = unEscapeChar(etk::String(list[iii], found+2));
|
||||||
value = removeStartAndStopSpace(value);
|
value = removeStartAndStopSpace(value);
|
||||||
ENET_VERBOSE("header : key='" << key << "' value='" << value << "'");
|
ENET_VERBOSE("header : key='" << key << "' value='" << value << "'");
|
||||||
if (m_isServer == false) {
|
if (m_isServer == false) {
|
||||||
@ -496,12 +545,13 @@ void enet::Http::getHeader() {
|
|||||||
m_connection.unlink();
|
m_connection.unlink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_headerIsSend = true;
|
||||||
if (m_isServer == false) {
|
if (m_isServer == false) {
|
||||||
if (m_observerAnswer != nullptr) {
|
if (m_observerAnswer != null) {
|
||||||
m_observerAnswer(m_answerHeader);
|
m_observerAnswer(m_answerHeader);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (m_observerRequest != nullptr) {
|
if (m_observerRequest != null) {
|
||||||
m_observerRequest(m_requestHeader);
|
m_observerRequest(m_requestHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,9 +559,9 @@ void enet::Http::getHeader() {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bool enet::Http::get(const std::string& _address) {
|
bool enet::Http::get(const etk::String& _address) {
|
||||||
m_header.m_map.clear();
|
m_header.m_map.clear();
|
||||||
std::string req = "GET http://" + m_connection.getName();
|
etk::String req = "GET http://" + m_connection.getName();
|
||||||
if (_address != "") {
|
if (_address != "") {
|
||||||
req += "/";
|
req += "/";
|
||||||
req += _address;
|
req += _address;
|
||||||
@ -536,10 +586,10 @@ bool enet::Http::get(const std::string& _address) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool enet::Http::post(const std::string& _address, const std::map<std::string, std::string>& _values) {
|
bool enet::Http::post(const etk::String& _address, const etk::Map<etk::String, etk::String>& _values) {
|
||||||
m_header.m_map.clear();
|
m_header.m_map.clear();
|
||||||
// First create body :
|
// First create body :
|
||||||
std::string body;
|
etk::String body;
|
||||||
for (auto &it : _values) {
|
for (auto &it : _values) {
|
||||||
if (body.size() > 0) {
|
if (body.size() > 0) {
|
||||||
body += "&";
|
body += "&";
|
||||||
@ -549,16 +599,16 @@ bool enet::Http::post(const std::string& _address, const std::map<std::string, s
|
|||||||
return post(_address, "application/x-www-form-urlencoded", body);
|
return post(_address, "application/x-www-form-urlencoded", body);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool enet::Http::post(const std::string& _address, const std::string& _contentType, const std::string& _data) {
|
bool enet::Http::post(const etk::String& _address, const etk::String& _contentType, const etk::String& _data) {
|
||||||
m_header.m_map.clear();
|
m_header.m_map.clear();
|
||||||
std::string req = "POST http://" + m_connection.getName();
|
etk::String req = "POST http://" + m_connection.getName();
|
||||||
if (_address != "") {
|
if (_address != "") {
|
||||||
req += "/";
|
req += "/";
|
||||||
req += _address;
|
req += _address;
|
||||||
}
|
}
|
||||||
req += " HTTP/1.0\n";
|
req += " HTTP/1.0\n";
|
||||||
setSendHeaderProperties("Content-Type", _contentType);
|
setSendHeaderProperties("Content-Type", _contentType);
|
||||||
setSendHeaderProperties("Content-Length", etk::to_string(_data.size()));
|
setSendHeaderProperties("Content-Length", etk::toString(_data.size()));
|
||||||
// add header properties :
|
// add header properties :
|
||||||
for (auto &it : m_header.m_map) {
|
for (auto &it : m_header.m_map) {
|
||||||
req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
|
req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
|
||||||
@ -583,23 +633,23 @@ int32_t enet::Http::write(const void* _data, int32_t _len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void enet::HttpHeader::setKey(const std::string& _key, const std::string& _value) {
|
void enet::HttpHeader::setKey(const etk::String& _key, const etk::String& _value) {
|
||||||
auto it = m_map.find(_key);
|
auto it = m_map.find(_key);
|
||||||
if (it == m_map.end()) {
|
if (it == m_map.end()) {
|
||||||
m_map.insert(make_pair(_key, _value));
|
m_map.add(_key, _value);
|
||||||
} else {
|
} else {
|
||||||
it->second = _value;
|
it->second = _value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::HttpHeader::rmKey(const std::string& _key) {
|
void enet::HttpHeader::rmKey(const etk::String& _key) {
|
||||||
auto it = m_map.find(_key);
|
auto it = m_map.find(_key);
|
||||||
if (it != m_map.end()) {
|
if (it != m_map.end()) {
|
||||||
m_map.erase(it);
|
m_map.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string enet::HttpHeader::getKey(const std::string& _key) const {
|
etk::String enet::HttpHeader::getKey(const etk::String& _key) const {
|
||||||
auto it = m_map.find(_key);
|
auto it = m_map.find(_key);
|
||||||
if (it != m_map.end()) {
|
if (it != m_map.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
@ -607,17 +657,64 @@ std::string enet::HttpHeader::getKey(const std::string& _key) const {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string enet::HttpHeader::generateKeys() const {
|
bool enet::HttpHeader::existKey(const etk::String& _key) const {
|
||||||
std::string out;
|
auto it = m_map.find(_key);
|
||||||
|
if (it != m_map.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
etk::String enet::HttpHeader::generateKeys() const {
|
||||||
|
etk::String out;
|
||||||
for (auto &it : m_map) {
|
for (auto &it : m_map) {
|
||||||
if ( it.first != ""
|
if ( it.first != ""
|
||||||
&& it.second != "") {
|
&& it.second != "") {
|
||||||
out += escapeChar(it.first) + " : " + escapeChar(it.second) + "\r\n";
|
out += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enet::HttpHeader::setQuery(const etk::Map<etk::String, etk::String>& _value) {
|
||||||
|
m_query = _value;
|
||||||
|
}
|
||||||
|
void enet::HttpHeader::setQueryKey(const etk::String& _key, const etk::String& _value) {
|
||||||
|
auto it = m_query.find(_key);
|
||||||
|
if (it == m_query.end()) {
|
||||||
|
m_query.add(_key, _value);
|
||||||
|
} else {
|
||||||
|
it->second = _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enet::HttpHeader::rmQueryKey(const etk::String& _key) {
|
||||||
|
auto it = m_query.find(_key);
|
||||||
|
if (it != m_query.end()) {
|
||||||
|
m_query.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
etk::String enet::HttpHeader::getQueryKey(const etk::String& _key) const {
|
||||||
|
auto it = m_query.find(_key);
|
||||||
|
if (it != m_query.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enet::HttpHeader::existQueryKey(const etk::String& _key) const {
|
||||||
|
auto it = m_query.find(_key);
|
||||||
|
if (it != m_query.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
etk::String enet::HttpHeader::generateQueryKeys() const {
|
||||||
|
return enet::pourcentUriEncode(m_query);
|
||||||
|
}
|
||||||
|
|
||||||
enet::HttpHeader::HttpHeader():
|
enet::HttpHeader::HttpHeader():
|
||||||
m_protocol(enet::HTTPProtocol::http_1_0) {
|
m_protocol(enet::HTTPProtocol::http_1_0) {
|
||||||
|
|
||||||
@ -627,7 +724,7 @@ enet::HttpHeader::HttpHeader():
|
|||||||
// -----------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
enet::HttpAnswer::HttpAnswer(enum HTTPAnswerCode _code, const std::string& _help):
|
enet::HttpAnswer::HttpAnswer(enum HTTPAnswerCode _code, const etk::String& _help):
|
||||||
m_what(_code),
|
m_what(_code),
|
||||||
m_helpMessage(_help) {
|
m_helpMessage(_help) {
|
||||||
|
|
||||||
@ -645,19 +742,26 @@ void enet::HttpAnswer::display() const {
|
|||||||
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ENET_PRINT(" query:");
|
||||||
|
for (auto &it : m_query) {
|
||||||
|
if ( it.first != ""
|
||||||
|
&& it.second != "") {
|
||||||
|
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string enet::HttpAnswer::generate() const {
|
etk::String enet::HttpAnswer::generate() const {
|
||||||
std::string out;
|
etk::String out;
|
||||||
out += etk::to_string(m_protocol);
|
out += etk::toString(m_protocol);
|
||||||
out += " ";
|
out += " ";
|
||||||
out += etk::to_string(int32_t(m_what));
|
out += etk::toString(int32_t(m_what));
|
||||||
out += " ";
|
out += " ";
|
||||||
if (m_helpMessage != "") {
|
if (m_helpMessage != "") {
|
||||||
out += escapeChar(m_helpMessage);
|
out += escapeChar(m_helpMessage);
|
||||||
} else {
|
} else {
|
||||||
auto it = protocolName.find(m_what);
|
auto it = getProtocolName().find(m_what);
|
||||||
if (it != protocolName.end()) {
|
if (it != getProtocolName().end()) {
|
||||||
out += escapeChar(it->second);
|
out += escapeChar(it->second);
|
||||||
} else {
|
} else {
|
||||||
out += "???";
|
out += "???";
|
||||||
@ -669,12 +773,12 @@ std::string enet::HttpAnswer::generate() const {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
enet::HttpServer::HttpServer(enet::Tcp _connection) :
|
enet::HttpServer::HttpServer(enet::Tcp _connection) :
|
||||||
enet::Http(std::move(_connection), true) {
|
enet::Http(etk::move(_connection), true) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enet::HttpClient::HttpClient(enet::Tcp _connection) :
|
enet::HttpClient::HttpClient(enet::Tcp _connection) :
|
||||||
enet::Http(std::move(_connection), false) {
|
enet::Http(etk::move(_connection), false) {
|
||||||
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------
|
||||||
@ -697,15 +801,26 @@ void enet::HttpRequest::display() const {
|
|||||||
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ENET_PRINT(" query:");
|
||||||
|
for (auto &it : m_query) {
|
||||||
|
if ( it.first != ""
|
||||||
|
&& it.second != "") {
|
||||||
|
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string enet::HttpRequest::generate() const {
|
etk::String enet::HttpRequest::generate() const {
|
||||||
std::string out;
|
etk::String out;
|
||||||
out += etk::to_string(m_req);
|
out += etk::toString(m_req);
|
||||||
out += " ";
|
out += " ";
|
||||||
out += m_uri;
|
out += m_uri;
|
||||||
|
etk::String querryData = generateQueryKeys();
|
||||||
|
if (querryData.empty() != 0) {
|
||||||
|
out += "?" + querryData;
|
||||||
|
}
|
||||||
out += " ";
|
out += " ";
|
||||||
out += etk::to_string(m_protocol);
|
out += etk::toString(m_protocol);
|
||||||
out += "\r\n";
|
out += "\r\n";
|
||||||
out += generateKeys();
|
out += generateKeys();
|
||||||
out += "\r\n";
|
out += "\r\n";
|
||||||
@ -713,17 +828,17 @@ std::string enet::HttpRequest::generate() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPProtocol _obj) {
|
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPProtocol _obj) {
|
||||||
_os << "enet::HTTPProtocol::" <<etk::to_string(_obj);
|
_os << "enet::HTTPProtocol::" <<etk::toString(_obj);
|
||||||
return _os;
|
return _os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj) {
|
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPAnswerCode _obj) {
|
||||||
_os << "enet::HTTPAnswerCode::" << etk::to_string(_obj);
|
_os << "enet::HTTPAnswerCode::" << etk::toString(_obj);
|
||||||
return _os;
|
return _os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPReqType _obj) {
|
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPReqType _obj) {
|
||||||
_os << "enet::HTTPReqType::" << etk::to_string(_obj);
|
_os << "enet::HTTPReqType::" << etk::toString(_obj);
|
||||||
return _os;
|
return _os;
|
||||||
}
|
}
|
@ -1,15 +1,16 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enet/Tcp.hpp>
|
#include <enet/Tcp.hpp>
|
||||||
#include <vector>
|
#include <etk/Vector.hpp>
|
||||||
#include <map>
|
#include <etk/Map.hpp>
|
||||||
#include <thread>
|
#include <ethread/Thread.hpp>
|
||||||
#include <ethread/tools.hpp>
|
#include <ethread/tools.hpp>
|
||||||
|
#include <etk/Function.hpp>
|
||||||
|
|
||||||
namespace enet {
|
namespace enet {
|
||||||
enum class HTTPAnswerCode {
|
enum class HTTPAnswerCode {
|
||||||
@ -63,7 +64,7 @@ namespace enet {
|
|||||||
c505_httpVersionNotSupported, //!< The server does not support the HTTP protocol version used in the request
|
c505_httpVersionNotSupported, //!< The server does not support the HTTP protocol version used in the request
|
||||||
c511_networkAuthenticationRequired, //!< The client needs to authenticate to gain network access
|
c511_networkAuthenticationRequired, //!< The client needs to authenticate to gain network access
|
||||||
};
|
};
|
||||||
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj);
|
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPAnswerCode _obj);
|
||||||
|
|
||||||
enum class HTTPProtocol {
|
enum class HTTPProtocol {
|
||||||
http_0_1,
|
http_0_1,
|
||||||
@ -110,18 +111,28 @@ namespace enet {
|
|||||||
http_3_9,
|
http_3_9,
|
||||||
http_3_10,
|
http_3_10,
|
||||||
};
|
};
|
||||||
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPProtocol _obj);
|
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPProtocol _obj);
|
||||||
class HttpHeader {
|
class HttpHeader {
|
||||||
protected:
|
protected:
|
||||||
// key, val
|
// key, val
|
||||||
std::map<std::string, std::string> m_map;
|
etk::Map<etk::String, etk::String> m_map;
|
||||||
|
etk::Map<etk::String, etk::String> m_query;
|
||||||
enum HTTPProtocol m_protocol;
|
enum HTTPProtocol m_protocol;
|
||||||
public:
|
public:
|
||||||
void setKey(const std::string& _key, const std::string& _value);
|
void setKey(const etk::String& _key, const etk::String& _value);
|
||||||
void rmKey(const std::string& _key);
|
void rmKey(const etk::String& _key);
|
||||||
std::string getKey(const std::string& _key) const;
|
etk::String getKey(const etk::String& _key) const;
|
||||||
|
bool existKey(const etk::String& _key) const;
|
||||||
protected:
|
protected:
|
||||||
std::string generateKeys() const;
|
etk::String generateKeys() const;
|
||||||
|
public:
|
||||||
|
void setQuery(const etk::Map<etk::String, etk::String>& _value);
|
||||||
|
void setQueryKey(const etk::String& _key, const etk::String& _value);
|
||||||
|
void rmQueryKey(const etk::String& _key);
|
||||||
|
etk::String getQueryKey(const etk::String& _key) const;
|
||||||
|
bool existQueryKey(const etk::String& _key) const;
|
||||||
|
protected:
|
||||||
|
etk::String generateQueryKeys() const;
|
||||||
public:
|
public:
|
||||||
enum HTTPProtocol getProtocol() const {
|
enum HTTPProtocol getProtocol() const {
|
||||||
return m_protocol;
|
return m_protocol;
|
||||||
@ -131,27 +142,27 @@ namespace enet {
|
|||||||
}
|
}
|
||||||
HttpHeader();
|
HttpHeader();
|
||||||
virtual ~HttpHeader() = default;
|
virtual ~HttpHeader() = default;
|
||||||
virtual std::string generate() const = 0;
|
virtual etk::String generate() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HttpAnswer : public HttpHeader {
|
class HttpAnswer : public HttpHeader {
|
||||||
private:
|
private:
|
||||||
enet::HTTPAnswerCode m_what;
|
enet::HTTPAnswerCode m_what;
|
||||||
std::string m_helpMessage;
|
etk::String m_helpMessage;
|
||||||
public:
|
public:
|
||||||
HttpAnswer(enum HTTPAnswerCode _code = enet::HTTPAnswerCode::c400_badRequest, const std::string& _help="");
|
HttpAnswer(enum HTTPAnswerCode _code = enet::HTTPAnswerCode::c400_badRequest, const etk::String& _help="");
|
||||||
void display() const;
|
void display() const;
|
||||||
std::string generate() const;
|
etk::String generate() const;
|
||||||
void setErrorCode(enum HTTPAnswerCode _value) {
|
void setErrorCode(enum HTTPAnswerCode _value) {
|
||||||
m_what = _value;
|
m_what = _value;
|
||||||
}
|
}
|
||||||
enum HTTPAnswerCode getErrorCode() const {
|
enum HTTPAnswerCode getErrorCode() const {
|
||||||
return m_what;
|
return m_what;
|
||||||
}
|
}
|
||||||
void setHelp(const std::string& _value) {
|
void setHelp(const etk::String& _value) {
|
||||||
m_helpMessage = _value;
|
m_helpMessage = _value;
|
||||||
}
|
}
|
||||||
const std::string& getHelp() const {
|
const etk::String& getHelp() const {
|
||||||
return m_helpMessage;
|
return m_helpMessage;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -161,27 +172,28 @@ namespace enet {
|
|||||||
HTTP_POST,
|
HTTP_POST,
|
||||||
HTTP_PUT,
|
HTTP_PUT,
|
||||||
HTTP_DELETE,
|
HTTP_DELETE,
|
||||||
|
HTTP_OPTIONS,
|
||||||
};
|
};
|
||||||
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPReqType _obj);
|
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPReqType _obj);
|
||||||
class HttpRequest : public HttpHeader {
|
class HttpRequest : public HttpHeader {
|
||||||
private:
|
private:
|
||||||
// key, val
|
// key, val
|
||||||
enum HTTPReqType m_req;
|
enum HTTPReqType m_req;
|
||||||
std::string m_uri;
|
etk::String m_uri;
|
||||||
public:
|
public:
|
||||||
HttpRequest(enum enet::HTTPReqType _type=enet::HTTPReqType::HTTP_GET);
|
HttpRequest(enum enet::HTTPReqType _type=enet::HTTPReqType::HTTP_GET);
|
||||||
void display() const;
|
void display() const;
|
||||||
std::string generate() const;
|
etk::String generate() const;
|
||||||
void setType(enum enet::HTTPReqType _value) {
|
void setType(enum enet::HTTPReqType _value) {
|
||||||
m_req = _value;
|
m_req = _value;
|
||||||
}
|
}
|
||||||
enum enet::HTTPReqType getType() const{
|
enum enet::HTTPReqType getType() const{
|
||||||
return m_req;
|
return m_req;
|
||||||
}
|
}
|
||||||
void setUri(const std::string& _value) {
|
void setUri(const etk::String& _value) {
|
||||||
m_uri = _value;
|
m_uri = _value;
|
||||||
}
|
}
|
||||||
const std::string& getUri() const {
|
const etk::String& getUri() const {
|
||||||
return m_uri;
|
return m_uri;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -215,9 +227,17 @@ namespace enet {
|
|||||||
protected:
|
protected:
|
||||||
enet::Tcp m_connection;
|
enet::Tcp m_connection;
|
||||||
bool m_headerIsSend;
|
bool m_headerIsSend;
|
||||||
std::thread* m_thread;
|
ethread::Thread* m_thread;
|
||||||
bool m_threadRunning;
|
bool m_threadRunning;
|
||||||
std::vector<uint8_t> m_temporaryBuffer;
|
etk::Vector<uint8_t> m_temporaryBuffer;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get the adress of the connection source IP:port
|
||||||
|
* @return string with the remote address name.
|
||||||
|
*/
|
||||||
|
const etk::String& getRemoteAddress() const {
|
||||||
|
return m_connection.getRemoteName();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void threadCallback();
|
void threadCallback();
|
||||||
private:
|
private:
|
||||||
@ -229,7 +249,14 @@ namespace enet {
|
|||||||
return m_connection.getConnectionStatus() == enet::Tcp::status::link;
|
return m_connection.getConnectionStatus() == enet::Tcp::status::link;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
using Observer = std::function<void(std::vector<uint8_t>&)>; //!< Define an Observer: function pointer
|
/**
|
||||||
|
* @brief Redirect the current HTTP request to an other network address.
|
||||||
|
* @param[in] _addressRedirect new redirection address:port
|
||||||
|
* @param[in] _inThreadStop the http thread request an auto-stop.
|
||||||
|
*/
|
||||||
|
void redirectTo(const etk::String& _addressRedirect, bool _inThreadStop=false);
|
||||||
|
public:
|
||||||
|
using Observer = etk::Function<void(etk::Vector<uint8_t>&)>; //!< Define an Observer: function pointer
|
||||||
Observer m_observer;
|
Observer m_observer;
|
||||||
/**
|
/**
|
||||||
* @brief Connect an function member on the signal with the shared_ptr object.
|
* @brief Connect an function member on the signal with the shared_ptr object.
|
||||||
@ -238,8 +265,8 @@ namespace enet {
|
|||||||
* @param[in] _args Argument optinnal the user want to add.
|
* @param[in] _args Argument optinnal the user want to add.
|
||||||
*/
|
*/
|
||||||
template<class CLASS_TYPE>
|
template<class CLASS_TYPE>
|
||||||
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(std::vector<uint8_t>&)) {
|
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(etk::Vector<uint8_t>&)) {
|
||||||
m_observer = [=](std::vector<uint8_t>& _value){
|
m_observer = [=](etk::Vector<uint8_t>& _value){
|
||||||
(*_class.*_func)(_value);
|
(*_class.*_func)(_value);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -247,7 +274,7 @@ namespace enet {
|
|||||||
m_observer = _func;
|
m_observer = _func;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
using ObserverRaw = std::function<void(enet::Tcp&)>; //!< Define an Observer: function pointer
|
using ObserverRaw = etk::Function<void(enet::Tcp&)>; //!< Define an Observer: function pointer
|
||||||
ObserverRaw m_observerRaw;
|
ObserverRaw m_observerRaw;
|
||||||
/**
|
/**
|
||||||
* @brief Connect an function member on the signal with the shared_ptr object.
|
* @brief Connect an function member on the signal with the shared_ptr object.
|
||||||
@ -265,11 +292,11 @@ namespace enet {
|
|||||||
m_observerRaw = _func;
|
m_observerRaw = _func;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
using ObserverRequest = std::function<void(const enet::HttpRequest&)>; //!< Define an Observer: function pointer
|
using ObserverRequest = etk::Function<void(const enet::HttpRequest&)>; //!< Define an Observer: function pointer
|
||||||
protected:
|
protected:
|
||||||
ObserverRequest m_observerRequest;
|
ObserverRequest m_observerRequest;
|
||||||
public:
|
public:
|
||||||
using ObserverAnswer = std::function<void(const enet::HttpAnswer&)>; //!< Define an Observer: function pointer
|
using ObserverAnswer = etk::Function<void(const enet::HttpAnswer&)>; //!< Define an Observer: function pointer
|
||||||
protected:
|
protected:
|
||||||
ObserverAnswer m_observerAnswer;
|
ObserverAnswer m_observerAnswer;
|
||||||
public:
|
public:
|
||||||
@ -288,7 +315,7 @@ namespace enet {
|
|||||||
* @return >0 byte size on the socket write
|
* @return >0 byte size on the socket write
|
||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
*/
|
*/
|
||||||
int32_t write(const std::string& _data, bool _writeBackSlashZero = true) {
|
int32_t write(const etk::String& _data, bool _writeBackSlashZero = true) {
|
||||||
if (_data.size() == 0) {
|
if (_data.size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -305,7 +332,7 @@ namespace enet {
|
|||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
int32_t write(const std::vector<T>& _data) {
|
int32_t write(const etk::Vector<T>& _data) {
|
||||||
if (_data.size() == 0) {
|
if (_data.size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -322,12 +349,13 @@ namespace enet {
|
|||||||
HttpClient(enet::Tcp _connection);
|
HttpClient(enet::Tcp _connection);
|
||||||
public:
|
public:
|
||||||
void setHeader(const enet::HttpRequest& _header) {
|
void setHeader(const enet::HttpRequest& _header) {
|
||||||
|
_header.display();
|
||||||
setRequestHeader(_header);
|
setRequestHeader(_header);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
//bool get(const std::string& _address);
|
//bool get(const etk::String& _address);
|
||||||
//bool post(const std::string& _address, const std::map<std::string, std::string>& _values);
|
//bool post(const etk::String& _address, const etk::Map<etk::String, etk::String>& _values);
|
||||||
//bool post(const std::string& _address, const std::string& _contentType, const std::string& _data);
|
//bool post(const etk::String& _address, const etk::String& _contentType, const etk::String& _data);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Connect an function member on the signal with the shared_ptr object.
|
* @brief Connect an function member on the signal with the shared_ptr object.
|
||||||
@ -351,6 +379,7 @@ namespace enet {
|
|||||||
HttpServer(enet::Tcp _connection);
|
HttpServer(enet::Tcp _connection);
|
||||||
public:
|
public:
|
||||||
void setHeader(const enet::HttpAnswer& _header) {
|
void setHeader(const enet::HttpAnswer& _header) {
|
||||||
|
_header.display();
|
||||||
setAnswerHeader(_header);
|
setAnswerHeader(_header);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
65
enet/Tcp.cpp
65
enet/Tcp.cpp
@ -1,16 +1,19 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
#include <enet/Tcp.hpp>
|
#include <enet/Tcp.hpp>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <cerrno>
|
extern "C" {
|
||||||
#include <unistd.h>
|
#include <errno.h>
|
||||||
#include <cstring>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
}
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
|
#include <ethread/tools.hpp>
|
||||||
|
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
@ -22,6 +25,10 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENET_STORE_INPUT
|
||||||
|
static uint32_t baseID = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool enet::Tcp::setTCPNoDelay(bool _enabled) {
|
bool enet::Tcp::setTCPNoDelay(bool _enabled) {
|
||||||
if (m_socketId >= 0) {
|
if (m_socketId >= 0) {
|
||||||
int flag = _enabled==true?1:0;
|
int flag = _enabled==true?1:0;
|
||||||
@ -46,20 +53,29 @@ enet::Tcp::Tcp() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
enet::Tcp::Tcp(SOCKET _idSocket, const std::string& _name) :
|
enet::Tcp::Tcp(SOCKET _idSocket, const etk::String& _name, const etk::String& _remoteName) :
|
||||||
#else
|
#else
|
||||||
enet::Tcp::Tcp(int32_t _idSocket, const std::string& _name) :
|
enet::Tcp::Tcp(int32_t _idSocket, const etk::String& _name, const etk::String& _remoteName) :
|
||||||
#endif
|
#endif
|
||||||
m_socketId(_idSocket),
|
m_socketId(_idSocket),
|
||||||
m_name(_name),
|
m_name(_name),
|
||||||
|
m_remoteName(_remoteName),
|
||||||
m_status(status::link) {
|
m_status(status::link) {
|
||||||
|
#ifdef ENET_STORE_INPUT
|
||||||
|
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
|
||||||
|
m_nodeStoreInput.fileOpenWrite();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
enet::Tcp::Tcp(Tcp&& _obj) :
|
enet::Tcp::Tcp(Tcp&& _obj) :
|
||||||
m_socketId(_obj.m_socketId),
|
m_socketId(_obj.m_socketId),
|
||||||
m_name(_obj.m_name),
|
m_name(_obj.m_name),
|
||||||
|
m_remoteName(_obj.m_remoteName),
|
||||||
m_status(_obj.m_status) {
|
m_status(_obj.m_status) {
|
||||||
|
#ifdef ENET_STORE_INPUT
|
||||||
|
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
|
||||||
|
m_nodeStoreInput.fileOpenWrite();
|
||||||
|
#endif
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
_obj.m_socketId = INVALID_SOCKET;
|
_obj.m_socketId = INVALID_SOCKET;
|
||||||
#else
|
#else
|
||||||
@ -75,6 +91,10 @@ enet::Tcp::~Tcp() {
|
|||||||
|
|
||||||
enet::Tcp& enet::Tcp::operator = (enet::Tcp&& _obj) {
|
enet::Tcp& enet::Tcp::operator = (enet::Tcp&& _obj) {
|
||||||
unlink();
|
unlink();
|
||||||
|
#ifdef ENET_STORE_INPUT
|
||||||
|
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
|
||||||
|
m_nodeStoreInput.fileOpenWrite();
|
||||||
|
#endif
|
||||||
m_socketId = _obj.m_socketId;
|
m_socketId = _obj.m_socketId;
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
_obj.m_socketId = INVALID_SOCKET;
|
_obj.m_socketId = INVALID_SOCKET;
|
||||||
@ -89,20 +109,25 @@ enet::Tcp& enet::Tcp::operator = (enet::Tcp&& _obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool enet::Tcp::unlink() {
|
bool enet::Tcp::unlink() {
|
||||||
|
// prevent call while stoping ...
|
||||||
|
m_status = status::unlink;
|
||||||
if (m_socketId >= 0) {
|
if (m_socketId >= 0) {
|
||||||
ENET_INFO("Close socket (start)");
|
ENET_INFO("Close socket (start)");
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
shutdown(m_socketId, SD_BOTH);
|
shutdown(m_socketId, SD_BOTH);
|
||||||
|
// Release hand of the socket to permit the Select to exit ... ==> otherwise it lock ...
|
||||||
|
ethread::sleepMilliSeconds((20));
|
||||||
closesocket(m_socketId);
|
closesocket(m_socketId);
|
||||||
m_socketId = INVALID_SOCKET;
|
m_socketId = INVALID_SOCKET;
|
||||||
#else
|
#else
|
||||||
shutdown(m_socketId, SHUT_RDWR);
|
shutdown(m_socketId, SHUT_RDWR);
|
||||||
|
// Release hand of the socket to permit the Select to exit ... ==> otherwise it lock ...
|
||||||
|
ethread::sleepMilliSeconds((20));
|
||||||
close(m_socketId);
|
close(m_socketId);
|
||||||
m_socketId = -1;
|
m_socketId = -1;
|
||||||
#endif
|
#endif
|
||||||
ENET_INFO("Close socket (done)");
|
ENET_INFO("Close socket (done)");
|
||||||
}
|
}
|
||||||
m_status = status::unlink;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +146,9 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
|||||||
timeOutStruct.tv_usec = 0;
|
timeOutStruct.tv_usec = 0;
|
||||||
FD_ZERO(&sock);
|
FD_ZERO(&sock);
|
||||||
FD_SET(m_socketId,&sock);
|
FD_SET(m_socketId,&sock);
|
||||||
|
ENET_VERBOSE(" select ...");
|
||||||
int rc = select(m_socketId+1, &sock, NULL, NULL, &timeOutStruct);
|
int rc = select(m_socketId+1, &sock, NULL, NULL, &timeOutStruct);
|
||||||
|
ENET_VERBOSE(" select (done)");
|
||||||
// Check to see if the poll call failed.
|
// Check to see if the poll call failed.
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
ENET_ERROR(" select() failed");
|
ENET_ERROR(" select() failed");
|
||||||
@ -141,7 +168,7 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
|||||||
// Receive data on this connection until the recv fails with EWOULDBLOCK.
|
// Receive data on this connection until the recv fails with EWOULDBLOCK.
|
||||||
// If any other failure occurs, we will close the connection.
|
// If any other failure occurs, we will close the connection.
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
ethread::UniqueLock lock(m_mutex);
|
||||||
rc = recv(m_socketId, (char *)_data, _maxLen, 0);
|
rc = recv(m_socketId, (char *)_data, _maxLen, 0);
|
||||||
}
|
}
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@ -154,6 +181,7 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
|||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
ENET_INFO("Connection closed");
|
ENET_INFO("Connection closed");
|
||||||
closeConn = true;
|
closeConn = true;
|
||||||
|
size = 0;
|
||||||
}
|
}
|
||||||
if (closeConn == false) {
|
if (closeConn == false) {
|
||||||
// Data was received
|
// Data was received
|
||||||
@ -164,7 +192,9 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
|||||||
ENET_DEBUG(" Set status at remote close ...");
|
ENET_DEBUG(" Set status at remote close ...");
|
||||||
m_status = status::linkRemoteClose;
|
m_status = status::linkRemoteClose;
|
||||||
}
|
}
|
||||||
//#endif
|
#ifdef ENET_STORE_INPUT
|
||||||
|
m_nodeStoreInput.fileWrite(_data, 1, size);
|
||||||
|
#endif
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,10 +204,23 @@ int32_t enet::Tcp::write(const void* _data, int32_t _len) {
|
|||||||
ENET_ERROR("Can not write on unlink connection");
|
ENET_ERROR("Can not write on unlink connection");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (_data == null) {
|
||||||
|
ENET_ERROR("try write null data on TCP socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_len <= 0) {
|
||||||
|
if (_len == 0) {
|
||||||
|
ENET_WARNING("try write data with lenght=" << _len << " ==> bad case");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ENET_ERROR("try write data with lenght=" << _len << " ==> bad case");
|
||||||
|
elog::displayBacktrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
//ENET_DEBUG("write on socketid = " << m_socketId << " data@=" << int64_t(_data) << " size=" << _len );
|
//ENET_DEBUG("write on socketid = " << m_socketId << " data@=" << int64_t(_data) << " size=" << _len );
|
||||||
int32_t size;
|
int32_t size;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
ethread::UniqueLock lock(m_mutex);
|
||||||
size = ::send(m_socketId, (const char *)_data, _len, 0);
|
size = ::send(m_socketId, (const char *)_data, _len, 0);
|
||||||
}
|
}
|
||||||
if ( size != _len
|
if ( size != _len
|
||||||
|
38
enet/Tcp.hpp
38
enet/Tcp.hpp
@ -1,17 +1,24 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <etk/types.hpp>
|
#include <etk/types.hpp>
|
||||||
#include <mutex>
|
#include <ethread/Mutex.hpp>
|
||||||
|
#include <etk/Function.hpp>
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//#define ENET_STORE_INPUT
|
||||||
|
|
||||||
|
#ifdef ENET_STORE_INPUT
|
||||||
|
#include <etk/os/FSNode.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace enet {
|
namespace enet {
|
||||||
class Tcp {
|
class Tcp {
|
||||||
private:
|
private:
|
||||||
@ -20,13 +27,16 @@ namespace enet {
|
|||||||
#else
|
#else
|
||||||
int32_t m_socketId; //!< socket linux interface generic
|
int32_t m_socketId; //!< socket linux interface generic
|
||||||
#endif
|
#endif
|
||||||
std::mutex m_mutex;
|
#ifdef ENET_STORE_INPUT
|
||||||
|
etk::FSNode m_nodeStoreInput;
|
||||||
|
#endif
|
||||||
|
ethread::Mutex m_mutex;
|
||||||
public:
|
public:
|
||||||
Tcp();
|
Tcp();
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
Tcp(SOCKET _idSocket, const std::string& _name);
|
Tcp(SOCKET _idSocket, const etk::String& _name, const etk::String& _remoteName="");
|
||||||
#else
|
#else
|
||||||
Tcp(int32_t _idSocket, const std::string& _name);
|
Tcp(int32_t _idSocket, const etk::String& _name, const etk::String& _remoteName="");
|
||||||
#endif
|
#endif
|
||||||
// move constructor
|
// move constructor
|
||||||
Tcp(Tcp&& _obj);
|
Tcp(Tcp&& _obj);
|
||||||
@ -36,15 +46,25 @@ namespace enet {
|
|||||||
Tcp& operator= (Tcp& _obj) = delete;
|
Tcp& operator= (Tcp& _obj) = delete;
|
||||||
virtual ~Tcp();
|
virtual ~Tcp();
|
||||||
private:
|
private:
|
||||||
std::string m_name; //!< hostname/IP:port.
|
etk::String m_name; //!< hostname/IP:port.
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Get the decriptive name hot the host:port
|
* @brief Get the decriptive name hot the host:port
|
||||||
* @return the string requested
|
* @return the string requested
|
||||||
*/
|
*/
|
||||||
const std::string& getName() {
|
const etk::String& getName() const {
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
etk::String m_remoteName; //!< remote IP:port.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get the decriptive name hot the host:port
|
||||||
|
* @return the string requested
|
||||||
|
*/
|
||||||
|
const etk::String& getRemoteName() const {
|
||||||
|
return m_remoteName;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
enum class status {
|
enum class status {
|
||||||
unlink,
|
unlink,
|
||||||
@ -92,7 +112,7 @@ namespace enet {
|
|||||||
* @return >0 byte size on the socket write
|
* @return >0 byte size on the socket write
|
||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
*/
|
*/
|
||||||
int32_t write(const std::string& _data, bool _writeBackSlashZero = true) {
|
int32_t write(const etk::String& _data, bool _writeBackSlashZero = true) {
|
||||||
if (_data.size() == 0) {
|
if (_data.size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -109,7 +129,7 @@ namespace enet {
|
|||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
int32_t write(const std::vector<T>& _data) {
|
int32_t write(const etk::Vector<T>& _data) {
|
||||||
if (_data.size() == 0) {
|
if (_data.size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
#include <enet/Tcp.hpp>
|
#include <enet/Tcp.hpp>
|
||||||
#include <enet/TcpClient.hpp>
|
#include <enet/TcpClient.hpp>
|
||||||
#include <enet/enet.hpp>
|
#include <enet/enet.hpp>
|
||||||
#include <sys/types.h>
|
extern "C" {
|
||||||
#include <cerrno>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <errno.h>
|
||||||
#include <cstring>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
}
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
|
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
@ -19,34 +21,53 @@
|
|||||||
#else
|
#else
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry) {
|
enet::Tcp enet::connectTcpClient(const etk::String& _config, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||||
std::string tmpname;
|
size_t pos = _config.find(':');
|
||||||
tmpname = etk::to_string(_ip1);
|
if (pos == etk::String::npos) {
|
||||||
|
return etk::move(enet::connectTcpClient(_config, 0, _numberRetry, _timeOut));
|
||||||
|
}
|
||||||
|
return etk::move(enet::connectTcpClient(_config.extract(0, pos),
|
||||||
|
etk::string_to_uint16_t(_config.extract(pos+1)),
|
||||||
|
_numberRetry,
|
||||||
|
_timeOut));
|
||||||
|
}
|
||||||
|
|
||||||
|
enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||||
|
etk::String tmpname;
|
||||||
|
tmpname = etk::toString(_ip1);
|
||||||
tmpname += ".";
|
tmpname += ".";
|
||||||
tmpname += etk::to_string(_ip2);
|
tmpname += etk::toString(_ip2);
|
||||||
tmpname += ".";
|
tmpname += ".";
|
||||||
tmpname += etk::to_string(_ip3);
|
tmpname += etk::toString(_ip3);
|
||||||
tmpname += ".";
|
tmpname += ".";
|
||||||
tmpname += etk::to_string(_ip4);
|
tmpname += etk::toString(_ip4);
|
||||||
return std::move(enet::connectTcpClient(tmpname, _port, _numberRetry));
|
return etk::move(enet::connectTcpClient(tmpname, _port, _numberRetry, _timeOut));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
enet::Tcp enet::connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry) {
|
enet::Tcp enet::connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||||
if (enet::isInit() == false) {
|
if (enet::isInit() == false) {
|
||||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||||
return std::move(enet::Tcp());
|
return etk::move(enet::Tcp());
|
||||||
|
}
|
||||||
|
if (_hostname == "") {
|
||||||
|
ENET_ERROR("get connection wihtout hostname");
|
||||||
|
return etk::move(enet::Tcp());
|
||||||
}
|
}
|
||||||
SOCKET socketId = INVALID_SOCKET;
|
SOCKET socketId = INVALID_SOCKET;
|
||||||
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
||||||
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
||||||
|
if (iii > 0) {
|
||||||
|
ethread::sleepMilliSeconds((200));
|
||||||
|
}
|
||||||
// open in Socket normal mode
|
// open in Socket normal mode
|
||||||
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (socketId < 0) {
|
if (socketId < 0) {
|
||||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
||||||
@ -58,18 +79,17 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
|
|||||||
hints.ai_protocol = IPPROTO_TCP;
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
// Resolve the server address and port
|
// Resolve the server address and port
|
||||||
struct addrinfo* result = nullptr;
|
struct addrinfo* result = null;
|
||||||
std::string portValue = etk::to_string(_port);
|
etk::String portValue = etk::toString(_port);
|
||||||
int iResult = getaddrinfo(_hostname.c_str(), portValue.c_str(), &hints, &result);
|
int iResult = getaddrinfo(_hostname.c_str(), portValue.c_str(), &hints, &result);
|
||||||
if (iResult != 0) {
|
if (iResult != 0) {
|
||||||
ENET_ERROR("getaddrinfo failed with error: " << iResult);
|
ENET_ERROR("getaddrinfo failed with error: " << iResult);
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to connect to an address until one succeeds
|
// Attempt to connect to an address until one succeeds
|
||||||
for(struct addrinfo* ptr=result;
|
for(struct addrinfo* ptr=result;
|
||||||
ptr != nullptr;
|
ptr != null;
|
||||||
ptr=ptr->ai_next) {
|
ptr=ptr->ai_next) {
|
||||||
ENET_DEBUG(" find one ...");
|
ENET_DEBUG(" find one ...");
|
||||||
// Create a SOCKET for connecting to server
|
// Create a SOCKET for connecting to server
|
||||||
@ -92,7 +112,6 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
|
|||||||
|
|
||||||
if (socketId == INVALID_SOCKET) {
|
if (socketId == INVALID_SOCKET) {
|
||||||
ENET_ERROR("Unable to connect to server!");
|
ENET_ERROR("Unable to connect to server!");
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -100,34 +119,56 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
|
|||||||
}
|
}
|
||||||
if (socketId == INVALID_SOCKET) {
|
if (socketId == INVALID_SOCKET) {
|
||||||
ENET_ERROR("ERROR connecting ... (after all try)");
|
ENET_ERROR("ERROR connecting ... (after all try)");
|
||||||
return std::move(enet::Tcp());
|
return etk::move(enet::Tcp());
|
||||||
}
|
}
|
||||||
ENET_DEBUG("Connection done");
|
ENET_DEBUG("Connection done");
|
||||||
return std::move(enet::Tcp(socketId, _hostname + ":" + etk::to_string(_port)));
|
return etk::move(enet::Tcp(socketId, _hostname + ":" + etk::toString(_port)));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
enet::Tcp enet::connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry) {
|
enet::Tcp enet::connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||||
if (enet::isInit() == false) {
|
if (enet::isInit() == false) {
|
||||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||||
return std::move(enet::Tcp());
|
return etk::move(enet::Tcp());
|
||||||
|
}
|
||||||
|
if (_hostname == "") {
|
||||||
|
ENET_ERROR("get connection wihtout hostname");
|
||||||
|
return etk::move(enet::Tcp());
|
||||||
}
|
}
|
||||||
int32_t socketId = -1;
|
int32_t socketId = -1;
|
||||||
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
||||||
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
||||||
|
if (iii > 0) {
|
||||||
|
ethread::sleepMilliSeconds((200));
|
||||||
|
}
|
||||||
// open in Socket normal mode
|
// open in Socket normal mode
|
||||||
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (socketId < 0) {
|
if (socketId < 0) {
|
||||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
||||||
struct sockaddr_in servAddr;
|
struct sockaddr_in servAddr;
|
||||||
struct hostent* server = gethostbyname(_hostname.c_str());
|
struct hostent* server = null;
|
||||||
if (server == nullptr) {
|
if ( _hostname.c_str()[0] >= '0'
|
||||||
|
&& _hostname.c_str()[0] <= '9') {
|
||||||
|
ENET_INFO("Calling gethostbyaddr with " << _hostname);
|
||||||
|
struct in_addr addr;
|
||||||
|
addr.s_addr = inet_addr(_hostname.c_str());
|
||||||
|
if (addr.s_addr == INADDR_NONE) {
|
||||||
|
ENET_ERROR("The IPv4 address entered must be a legal address" << _hostname.c_str());
|
||||||
|
return etk::move(enet::Tcp());
|
||||||
|
} else {
|
||||||
|
// TODO : This is deprecated use getaddrinfo like windows ...
|
||||||
|
server = gethostbyaddr((char *) &addr, 4, AF_INET);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ENET_INFO("Calling gethostbyname with " << _hostname);
|
||||||
|
// TODO : This is deprecated use getaddrinfo like windows ...
|
||||||
|
server = gethostbyname(_hostname.c_str());
|
||||||
|
}
|
||||||
|
if (server == null) {
|
||||||
ENET_ERROR("ERROR, no such host : " << _hostname);
|
ENET_ERROR("ERROR, no such host : " << _hostname);
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bzero((char *) &servAddr, sizeof(servAddr));
|
bzero((char *) &servAddr, sizeof(servAddr));
|
||||||
@ -135,7 +176,7 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
|
|||||||
bcopy((char *)server->h_addr, (char *)&servAddr.sin_addr.s_addr, server->h_length);
|
bcopy((char *)server->h_addr, (char *)&servAddr.sin_addr.s_addr, server->h_length);
|
||||||
servAddr.sin_port = htons(_port);
|
servAddr.sin_port = htons(_port);
|
||||||
ENET_INFO("Start connexion ...");
|
ENET_INFO("Start connexion ...");
|
||||||
if (connect(socketId, (struct sockaddr *)&servAddr,sizeof(servAddr)) != 0) {
|
if (connect(socketId, (struct sockaddr *)&servAddr, sizeof(servAddr)) != 0) {
|
||||||
if(errno != EINPROGRESS) {
|
if(errno != EINPROGRESS) {
|
||||||
if( errno != ENOENT
|
if( errno != ENOENT
|
||||||
&& errno != EAGAIN
|
&& errno != EAGAIN
|
||||||
@ -150,18 +191,16 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
|
|||||||
socketId = -1;
|
socketId = -1;
|
||||||
}
|
}
|
||||||
ENET_ERROR("ERROR connecting, maybe retry ... errno=" << errno << "," << strerror(errno));
|
ENET_ERROR("ERROR connecting, maybe retry ... errno=" << errno << "," << strerror(errno));
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if we are here ==> then the connextion is done corectly ...
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (socketId<0) {
|
if (socketId<0) {
|
||||||
ENET_ERROR("ERROR connecting ... (after all try)");
|
ENET_ERROR("ERROR connecting ... (after all try)");
|
||||||
return std::move(enet::Tcp());
|
return etk::move(enet::Tcp());
|
||||||
}
|
}
|
||||||
ENET_DEBUG("Connection done");
|
ENET_INFO("Connection done");
|
||||||
return std::move(enet::Tcp(socketId, _hostname + ":" + etk::to_string(_port)));
|
return etk::move(enet::Tcp(socketId, _hostname + ":" + etk::toString(_port)));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enet/Tcp.hpp>
|
#include <enet/Tcp.hpp>
|
||||||
|
#include <echrono/Duration.hpp>
|
||||||
|
|
||||||
namespace enet {
|
namespace enet {
|
||||||
enet::Tcp connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry=5);
|
enet::Tcp connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry=5, echrono::Duration _timeOut = echrono::seconds(1));
|
||||||
enet::Tcp connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry=5);
|
enet::Tcp connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry=5, echrono::Duration _timeOut = echrono::seconds(1));
|
||||||
|
enet::Tcp connectTcpClient(const etk::String& _config, uint32_t _numberRetry, echrono::Duration _timeOut);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
#include <enet/Tcp.hpp>
|
#include <enet/Tcp.hpp>
|
||||||
#include <enet/TcpServer.hpp>
|
#include <enet/TcpServer.hpp>
|
||||||
#include <enet/enet.hpp>
|
#include <enet/enet.hpp>
|
||||||
#include <sys/types.h>
|
extern "C" {
|
||||||
#include <cerrno>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <errno.h>
|
||||||
#include <cstring>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
}
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
|
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
@ -37,18 +39,18 @@ enet::TcpServer::~TcpServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void enet::TcpServer::setIpV4(uint8_t _fist, uint8_t _second, uint8_t _third, uint8_t _quatro) {
|
void enet::TcpServer::setIpV4(uint8_t _fist, uint8_t _second, uint8_t _third, uint8_t _quatro) {
|
||||||
std::string tmpname;
|
etk::String tmpname;
|
||||||
tmpname = etk::to_string(_fist);
|
tmpname = etk::toString(_fist);
|
||||||
tmpname += ".";
|
tmpname += ".";
|
||||||
tmpname += etk::to_string(_second);
|
tmpname += etk::toString(_second);
|
||||||
tmpname += ".";
|
tmpname += ".";
|
||||||
tmpname += etk::to_string(_third);
|
tmpname += etk::toString(_third);
|
||||||
tmpname += ".";
|
tmpname += ".";
|
||||||
tmpname += etk::to_string(_quatro);
|
tmpname += etk::toString(_quatro);
|
||||||
setHostNane(tmpname);
|
setHostNane(tmpname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::TcpServer::setHostNane(const std::string& _name) {
|
void enet::TcpServer::setHostNane(const etk::String& _name) {
|
||||||
if (_name == m_host) {
|
if (_name == m_host) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -70,7 +72,7 @@ void enet::TcpServer::setPort(uint16_t _port) {
|
|||||||
}
|
}
|
||||||
ENET_INFO("Start connection on " << m_host << ":" << m_port);
|
ENET_INFO("Start connection on " << m_host << ":" << m_port);
|
||||||
|
|
||||||
struct addrinfo *result = nullptr;
|
struct addrinfo *result = null;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
ZeroMemory(&hints, sizeof(hints));
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
hints.ai_family = AF_INET;
|
hints.ai_family = AF_INET;
|
||||||
@ -79,8 +81,8 @@ void enet::TcpServer::setPort(uint16_t _port) {
|
|||||||
hints.ai_flags = AI_PASSIVE;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
// Resolve the server address and port
|
// Resolve the server address and port
|
||||||
std::string portValue = etk::to_string(m_port);
|
etk::String portValue = etk::toString(m_port);
|
||||||
int iResult = getaddrinfo(nullptr, portValue.c_str(), &hints, &result);
|
int iResult = getaddrinfo(null, portValue.c_str(), &hints, &result);
|
||||||
if (iResult != 0) {
|
if (iResult != 0) {
|
||||||
ENET_ERROR("getaddrinfo failed with error: " << iResult);
|
ENET_ERROR("getaddrinfo failed with error: " << iResult);
|
||||||
return 1;
|
return 1;
|
||||||
@ -153,7 +155,7 @@ void enet::TcpServer::setPort(uint16_t _port) {
|
|||||||
enet::Tcp enet::TcpServer::waitNext() {
|
enet::Tcp enet::TcpServer::waitNext() {
|
||||||
if (enet::isInit() == false) {
|
if (enet::isInit() == false) {
|
||||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||||
return std::move(enet::Tcp());
|
return etk::move(enet::Tcp());
|
||||||
}
|
}
|
||||||
ENET_INFO("End binding Socket ... (start listen)");
|
ENET_INFO("End binding Socket ... (start listen)");
|
||||||
#ifdef __TARGET_OS__Windows
|
#ifdef __TARGET_OS__Windows
|
||||||
@ -181,8 +183,57 @@ enet::Tcp enet::TcpServer::waitNext() {
|
|||||||
|
|
||||||
return enet::Tcp();
|
return enet::Tcp();
|
||||||
}
|
}
|
||||||
ENET_INFO("End configuring Socket ... Find New one");
|
etk::String remoteAddress;
|
||||||
return enet::Tcp(socketIdClient, m_host + ":" + etk::to_string(m_port));
|
{
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
|
socklen_t len = sizeof(addr);
|
||||||
|
getpeername(socketIdClient, (struct sockaddr*)&addr, &len);
|
||||||
|
// deal with both IPv4 and IPv6:
|
||||||
|
if (addr.ss_family == AF_INET) {
|
||||||
|
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||||
|
int port = ntohs(s->sin_port);
|
||||||
|
remoteAddress = etk::toString(s->sin_addr.s_addr&0xFF);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toString((s->sin_addr.s_addr>>8)&0xFF);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toString((s->sin_addr.s_addr>>16)&0xFF);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toString((s->sin_addr.s_addr>>24)&0xFF);
|
||||||
|
remoteAddress += ":";
|
||||||
|
remoteAddress += etk::toString(port);
|
||||||
|
} else { // AF_INET6
|
||||||
|
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
||||||
|
int port = ntohs(s->sin6_port);
|
||||||
|
remoteAddress = etk::toHex(s->sin6_addr.s6_addr[0], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[1], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[2], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[3], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[4], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[5], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[6], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[7], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[8], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[9], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[10], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[11], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[12], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[13], 2);
|
||||||
|
remoteAddress += ".";
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[14], 2);
|
||||||
|
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[15], 2);
|
||||||
|
remoteAddress += ":";
|
||||||
|
remoteAddress += etk::toString(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ENET_ERROR("End configuring Socket ... Find New one FROM " << remoteAddress);
|
||||||
|
return enet::Tcp(socketIdClient, m_host + ":" + etk::toString(m_port), remoteAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <enet/Tcp.hpp>
|
#include <enet/Tcp.hpp>
|
||||||
@ -26,7 +26,7 @@ namespace enet {
|
|||||||
TcpServer();
|
TcpServer();
|
||||||
virtual ~TcpServer();
|
virtual ~TcpServer();
|
||||||
private:
|
private:
|
||||||
std::string m_host; //!< hostname/IP to connect with.
|
etk::String m_host; //!< hostname/IP to connect with.
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Set the connection IP id.
|
* @brief Set the connection IP id.
|
||||||
@ -40,12 +40,12 @@ namespace enet {
|
|||||||
* @brief set the Host name is the same things as set an Ip adress, but in test mode "127.0.0.1" or "localhost".
|
* @brief set the Host name is the same things as set an Ip adress, but in test mode "127.0.0.1" or "localhost".
|
||||||
* @param[in] _name Host name to connect.
|
* @param[in] _name Host name to connect.
|
||||||
*/
|
*/
|
||||||
void setHostNane(const std::string& _name);
|
void setHostNane(const etk::String& _name);
|
||||||
/**
|
/**
|
||||||
* @brief Get the decriptive name hot the host
|
* @brief Get the decriptive name hot the host
|
||||||
* @return the string requested
|
* @return the string requested
|
||||||
*/
|
*/
|
||||||
const std::string& getHostName() {
|
const etk::String& getHostName() {
|
||||||
return m_host;
|
return m_host;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
#include <enet/WebSocket.hpp>
|
#include <enet/WebSocket.hpp>
|
||||||
#include <map>
|
#include <etk/Map.hpp>
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
#include <cstring>
|
#include <etk/String.hpp>
|
||||||
#include <random>
|
#include <etk/tool.hpp>
|
||||||
#include <algue/base64.hpp>
|
#include <algue/base64.hpp>
|
||||||
#include <algue/sha1.hpp>
|
#include <algue/sha1.hpp>
|
||||||
|
|
||||||
@ -29,54 +29,44 @@ namespace enet {
|
|||||||
|
|
||||||
enet::WebSocket::WebSocket() :
|
enet::WebSocket::WebSocket() :
|
||||||
m_connectionValidate(false),
|
m_connectionValidate(false),
|
||||||
m_interface(nullptr),
|
m_interface(null),
|
||||||
m_observer(nullptr),
|
m_observer(null),
|
||||||
m_observerUriCheck(nullptr) {
|
m_observerUriCheck(null) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enet::WebSocket::WebSocket(enet::Tcp _connection, bool _isServer) :
|
enet::WebSocket::WebSocket(enet::Tcp _connection, bool _isServer) :
|
||||||
m_connectionValidate(false),
|
m_connectionValidate(false),
|
||||||
m_interface(nullptr),
|
m_interface(null),
|
||||||
m_observer(nullptr),
|
m_observer(null),
|
||||||
m_observerUriCheck(nullptr) {
|
m_observerUriCheck(null) {
|
||||||
_connection.setTCPNoDelay(true);
|
setInterface(etk::move(_connection), _isServer);
|
||||||
if (_isServer == true) {
|
}
|
||||||
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(std::move(_connection));
|
|
||||||
m_interface = interface;
|
const etk::String& enet::WebSocket::getRemoteAddress() const {
|
||||||
if (interface != nullptr) {
|
if (m_interface == null) {
|
||||||
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
|
static const etk::String tmpOut;
|
||||||
}
|
return tmpOut;
|
||||||
} else {
|
|
||||||
ememory::SharedPtr<enet::HttpClient> interface = ememory::makeShared<enet::HttpClient>(std::move(_connection));
|
|
||||||
m_interface = interface;
|
|
||||||
if (interface != nullptr) {
|
|
||||||
interface->connectHeader(this, &enet::WebSocket::onReceiveAnswer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_interface == nullptr) {
|
return m_interface->getRemoteAddress();
|
||||||
ENET_ERROR("can not create interface for the websocket");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_interface->connectRaw(this, &enet::WebSocket::onReceiveData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
|
void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
|
||||||
_connection.setTCPNoDelay(true);
|
_connection.setTCPNoDelay(true);
|
||||||
if (_isServer == true) {
|
if (_isServer == true) {
|
||||||
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(std::move(_connection));
|
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(etk::move(_connection));
|
||||||
m_interface = interface;
|
m_interface = interface;
|
||||||
if (interface != nullptr) {
|
if (interface != null) {
|
||||||
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
|
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ememory::SharedPtr<enet::HttpClient> interface = ememory::makeShared<enet::HttpClient>(std::move(_connection));
|
ememory::SharedPtr<enet::HttpClient> interface = ememory::makeShared<enet::HttpClient>(etk::move(_connection));
|
||||||
m_interface = interface;
|
m_interface = interface;
|
||||||
if (interface != nullptr) {
|
if (interface != null) {
|
||||||
interface->connectHeader(this, &enet::WebSocket::onReceiveAnswer);
|
interface->connectHeader(this, &enet::WebSocket::onReceiveAnswer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("can not create interface for the websocket");
|
ENET_ERROR("can not create interface for the websocket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -84,84 +74,93 @@ void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enet::WebSocket::~WebSocket() {
|
enet::WebSocket::~WebSocket() {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stop(true);
|
stop(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string generateKey() {
|
static etk::String generateKey() {
|
||||||
// create dynamic key:
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 e2(rd());
|
|
||||||
std::uniform_real_distribution<> dist(0, 0xFF);
|
|
||||||
uint8_t dataKey[16];
|
uint8_t dataKey[16];
|
||||||
|
// create dynamic key:
|
||||||
for (size_t iii=0; iii<16; ++iii) {
|
for (size_t iii=0; iii<16; ++iii) {
|
||||||
dataKey[iii] = uint8_t(dist(e2));
|
dataKey[iii] = uint8_t(etk::tool::urand(0,255));
|
||||||
}
|
}
|
||||||
return algue::base64::encode(dataKey, 16);
|
return algue::base64::encode(dataKey, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string generateCheckKey(const std::string& _key) {
|
static etk::String generateCheckKey(const etk::String& _key) {
|
||||||
std::string out = _key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
etk::String out = _key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
std::vector<uint8_t> keyData = algue::sha1::encode(out);
|
etk::Vector<uint8_t> keyData = algue::sha1::encode(out);
|
||||||
return algue::base64::encode(keyData);
|
return algue::base64::encode(keyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::start(const std::string& _uri, const std::vector<std::string>& _listProtocols) {
|
void enet::WebSocket::start(const etk::String& _uri, const etk::Vector<etk::String>& _listProtocols) {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_interface->start();
|
if (m_interface->isServer() == true) {
|
||||||
if (m_interface->isServer() == false) {
|
m_interface->start();
|
||||||
enet::HttpRequest req(enet::HTTPReqType::HTTP_GET);
|
} else {
|
||||||
req.setProtocol(enet::HTTPProtocol::http_1_1);
|
do {
|
||||||
req.setUri(_uri);
|
m_redirectInProgress = false;
|
||||||
req.setKey("Upgrade", "websocket");
|
m_interface->start();
|
||||||
req.setKey("Connection", "Upgrade");
|
enet::HttpRequest req(enet::HTTPReqType::HTTP_GET);
|
||||||
m_checkKey = generateKey();
|
req.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||||
req.setKey("Sec-WebSocket-Key", m_checkKey); // this is an example key ...
|
req.setUri(_uri);
|
||||||
m_checkKey = generateCheckKey(m_checkKey);
|
req.setKey("Upgrade", "websocket");
|
||||||
req.setKey("Sec-WebSocket-Version", "13");
|
req.setKey("Connection", "Upgrade");
|
||||||
req.setKey("Pragma", "no-cache");
|
m_checkKey = generateKey();
|
||||||
req.setKey("Cache-Control", "no-cache");
|
req.setKey("Sec-WebSocket-Key", m_checkKey); // this is an example key ...
|
||||||
std::string protocolList;
|
m_checkKey = generateCheckKey(m_checkKey);
|
||||||
for (auto &it : _listProtocols) {
|
req.setKey("Sec-WebSocket-Version", "13");
|
||||||
if (it == "") {
|
req.setKey("Pragma", "no-cache");
|
||||||
continue;
|
req.setKey("Cache-Control", "no-cache");
|
||||||
|
etk::String protocolList;
|
||||||
|
for (auto &it : _listProtocols) {
|
||||||
|
if (it == "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (protocolList != "") {
|
||||||
|
protocolList += ", ";
|
||||||
|
}
|
||||||
|
protocolList += it;
|
||||||
}
|
}
|
||||||
if (protocolList != "") {
|
if (protocolList != "") {
|
||||||
protocolList += ", ";
|
req.setKey("Sec-WebSocket-Protocol", protocolList);
|
||||||
}
|
}
|
||||||
protocolList += it;
|
ememory::SharedPtr<enet::HttpClient> interface = ememory::dynamicPointerCast<enet::HttpClient>(m_interface);
|
||||||
}
|
if (interface != null) {
|
||||||
if (protocolList != "") {
|
interface->setHeader(req);
|
||||||
req.setKey("Sec-WebSocket-Protocol", protocolList);
|
int32_t timeout = 500000; // 5 second
|
||||||
}
|
while ( timeout>=0
|
||||||
ememory::SharedPtr<enet::HttpClient> interface = ememory::dynamicPointerCast<enet::HttpClient>(m_interface);
|
&& m_redirectInProgress == false) {
|
||||||
if (interface != nullptr) {
|
if ( m_connectionValidate == true
|
||||||
interface->setHeader(req);
|
|| m_interface->isAlive() == false) {
|
||||||
int32_t timeout = 500000; // 5 second
|
break;
|
||||||
while (timeout>=0) {
|
}
|
||||||
if ( m_connectionValidate == true
|
ethread::sleepMilliSeconds(10);
|
||||||
|| m_interface->isAlive() == false) {
|
timeout--;
|
||||||
break;
|
}
|
||||||
|
if (m_redirectInProgress == true) {
|
||||||
|
ENET_WARNING("Request a redirection (wait 500ms)");
|
||||||
|
ethread::sleepMilliSeconds(500);
|
||||||
|
ENET_WARNING("Request a redirection (wait-end)");
|
||||||
|
} else {
|
||||||
|
if ( m_connectionValidate == false
|
||||||
|
|| m_interface->isAlive() == false) {
|
||||||
|
ENET_ERROR("Connection refused by SERVER ...");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
timeout--;
|
|
||||||
}
|
}
|
||||||
if ( m_connectionValidate == false
|
} while (m_redirectInProgress == true);
|
||||||
|| m_interface->isAlive() == false) {
|
|
||||||
ENET_ERROR("Connection refused by SERVER ...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::stop(bool _inThread) {
|
void enet::WebSocket::stop(bool _inThread) {
|
||||||
ENET_DEBUG("Stop interface ...");
|
ENET_DEBUG("Stop interface ...");
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -185,15 +184,18 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
|||||||
ENET_VERBOSE("ReadRaw 2 [STOP]");
|
ENET_VERBOSE("ReadRaw 2 [STOP]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_lastReceive = std::chrono::steady_clock::now();
|
m_lastReceive = echrono::Steady::now();
|
||||||
if ((opcode & 0x80) == 0) {
|
if ((opcode & 0x80) == 0) {
|
||||||
ENET_ERROR("Multiple frames ... NOT managed ...");
|
ENET_ERROR("Multiple frames ... NOT managed ... : " << (opcode & 0x80) << (opcode & 0x40) << (opcode & 0x20) << (opcode & 0x10) << (opcode & 0x08) << (opcode & 0x04) << (opcode & 0x02) << (opcode & 0x01));
|
||||||
m_interface->stop(true);
|
m_interface->stop(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int8_t size1 = 0;
|
int8_t size1 = 0;
|
||||||
len = _connection.read(&size1, sizeof(uint8_t));
|
len = _connection.read(&size1, sizeof(uint8_t));
|
||||||
if (len <= 0) {
|
int32_t maxIteration = 50;
|
||||||
|
// We must get the payload size in all case ... ==> otherwise it create problems
|
||||||
|
while ( len <= 0
|
||||||
|
&& maxIteration > 0) {
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
if (_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
if (_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
||||||
ENET_ERROR("Protocol error occured ...");
|
ENET_ERROR("Protocol error occured ...");
|
||||||
@ -204,6 +206,12 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
|||||||
}
|
}
|
||||||
ENET_ERROR("Time out ... ==> not managed ...");
|
ENET_ERROR("Time out ... ==> not managed ...");
|
||||||
ENET_VERBOSE("ReadRaw 2 [STOP]");
|
ENET_VERBOSE("ReadRaw 2 [STOP]");
|
||||||
|
len = _connection.read(&size1, sizeof(uint8_t));
|
||||||
|
maxIteration--;
|
||||||
|
}
|
||||||
|
if (maxIteration <= 0) {
|
||||||
|
ENET_ERROR("Can not read the Socket >> auto kill");
|
||||||
|
m_interface->stop(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64_t totalSize = size1 & 0x7F;
|
uint64_t totalSize = size1 & 0x7F;
|
||||||
@ -283,32 +291,32 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
|||||||
// check opcode:
|
// check opcode:
|
||||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_CLOSE) {
|
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_CLOSE) {
|
||||||
// Close the conection by remote:
|
// Close the conection by remote:
|
||||||
ENET_INFO("Close connection by remote :");
|
ENET_WARNING("Close connection by remote :");
|
||||||
m_interface->stop(true);
|
m_interface->stop(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PING) {
|
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PING) {
|
||||||
// Close the conection by remote:
|
// Close the conection by remote:
|
||||||
ENET_DEBUG("Receive a ping (send a pong)");
|
ENET_WARNING("Receive a ping (send a pong)");
|
||||||
controlPong();
|
controlPong();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PONG) {
|
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PONG) {
|
||||||
// Close the conection by remote:
|
// Close the conection by remote:
|
||||||
ENET_DEBUG("Receive a pong");
|
ENET_WARNING("Receive a pong");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_TEXT) {
|
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_TEXT) {
|
||||||
// Close the conection by remote:
|
// Close the conection by remote:
|
||||||
ENET_DEBUG("Receive a Text(UTF-8) data " << m_buffer.size() << " Bytes");
|
ENET_WARNING("Receive a Text(UTF-8) data " << m_buffer.size() << " Bytes");
|
||||||
if (m_observer != nullptr) {
|
if (m_observer != null) {
|
||||||
m_observer(m_buffer, true);
|
m_observer(m_buffer, true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_BINARY) {
|
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_BINARY) {
|
||||||
// Close the conection by remote:
|
// Close the conection by remote:
|
||||||
if (m_observer != nullptr) {
|
if (m_observer != null) {
|
||||||
m_observer(m_buffer, false);
|
m_observer(m_buffer, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -316,8 +324,8 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
|||||||
ENET_ERROR("ReadRaw [STOP] (no opcode manage ... " << int32_t(opcode & 0x0F));
|
ENET_ERROR("ReadRaw [STOP] (no opcode manage ... " << int32_t(opcode & 0x0F));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string removeStartAndStopSpace(const std::string& _value) {
|
static etk::String removeStartAndStopSpace(const etk::String& _value) {
|
||||||
std::string out;
|
etk::String out;
|
||||||
out.reserve(_value.size());
|
out.reserve(_value.size());
|
||||||
bool findSpace = false;
|
bool findSpace = false;
|
||||||
for (auto &it : _value) {
|
for (auto &it : _value) {
|
||||||
@ -337,7 +345,7 @@ static std::string removeStartAndStopSpace(const std::string& _value) {
|
|||||||
|
|
||||||
void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||||
ememory::SharedPtr<enet::HttpServer> interface = ememory::dynamicPointerCast<enet::HttpServer>(m_interface);
|
ememory::SharedPtr<enet::HttpServer> interface = ememory::dynamicPointerCast<enet::HttpServer>(m_interface);
|
||||||
if (interface == nullptr) {
|
if (interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -375,16 +383,29 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// parse all protocols:
|
// parse all protocols:
|
||||||
std::vector<std::string> listProtocol;
|
etk::Vector<etk::String> listProtocol;
|
||||||
if (_data.getKey("Sec-WebSocket-Protocol") != "") {
|
if (_data.getKey("Sec-WebSocket-Protocol") != "") {
|
||||||
listProtocol = etk::split(_data.getKey("Sec-WebSocket-Protocol"),',');
|
listProtocol = etk::split(_data.getKey("Sec-WebSocket-Protocol"),',');
|
||||||
for (size_t iii=0; iii<listProtocol.size(); ++iii) {
|
for (size_t iii=0; iii<listProtocol.size(); ++iii) {
|
||||||
listProtocol[iii] = removeStartAndStopSpace(listProtocol[iii]);
|
listProtocol[iii] = removeStartAndStopSpace(listProtocol[iii]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_observerUriCheck != null) {
|
||||||
if (m_observerUriCheck != nullptr) {
|
etk::String ret = m_observerUriCheck(_data.getUri(), listProtocol);
|
||||||
if (m_observerUriCheck(_data.getUri(), listProtocol) == false) {
|
if (ret == "OK") {
|
||||||
|
// Nothing to do
|
||||||
|
} else if (ret.startWith("REDIRECT:") == true) {
|
||||||
|
ENET_INFO("Request redirection of HTTP/WebSocket connection to : '" << ret.extract(9, ret.size()) << "'");
|
||||||
|
enet::HttpAnswer answer(enet::HTTPAnswerCode::c307_temporaryRedirect);
|
||||||
|
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||||
|
answer.setKey("Location", ret.extract(9, ret.size()));
|
||||||
|
interface->setHeader(answer);
|
||||||
|
interface->stop(true);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (ret != "CLOSE") {
|
||||||
|
ENET_ERROR("UNKNOW return type of URI request: '" << ret << "'");
|
||||||
|
}
|
||||||
enet::HttpAnswer answer(enet::HTTPAnswerCode::c404_notFound);
|
enet::HttpAnswer answer(enet::HTTPAnswerCode::c404_notFound);
|
||||||
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||||
answer.setKey("Connection", "close");
|
answer.setKey("Connection", "close");
|
||||||
@ -397,7 +418,7 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
|||||||
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||||
answer.setKey("Upgrade", "websocket");
|
answer.setKey("Upgrade", "websocket");
|
||||||
answer.setKey("Connection", "Upgrade");
|
answer.setKey("Connection", "Upgrade");
|
||||||
std::string answerKey = generateCheckKey(_data.getKey("Sec-WebSocket-Key"));
|
etk::String answerKey = generateCheckKey(_data.getKey("Sec-WebSocket-Key"));
|
||||||
answer.setKey("Sec-WebSocket-Accept", answerKey);
|
answer.setKey("Sec-WebSocket-Accept", answerKey);
|
||||||
if (m_protocol != "") {
|
if (m_protocol != "") {
|
||||||
answer.setKey("Sec-WebSocket-Protocol", m_protocol);
|
answer.setKey("Sec-WebSocket-Protocol", m_protocol);
|
||||||
@ -406,11 +427,19 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::onReceiveAnswer(const enet::HttpAnswer& _data) {
|
void enet::WebSocket::onReceiveAnswer(const enet::HttpAnswer& _data) {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_data.display();
|
_data.display();
|
||||||
|
if (_data.getErrorCode() == enet::HTTPAnswerCode::c307_temporaryRedirect) {
|
||||||
|
ENET_ERROR("Request connection redirection to '" << _data.getKey("Location") << "'");
|
||||||
|
// We are a client mode, we need to recreate a TCP connection on the new remote interface
|
||||||
|
// This is the generic way to accept a redirection
|
||||||
|
m_redirectInProgress = true;
|
||||||
|
m_interface->redirectTo(_data.getKey("Location"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_data.getErrorCode() != enet::HTTPAnswerCode::c101_switchingProtocols) {
|
if (_data.getErrorCode() != enet::HTTPAnswerCode::c101_switchingProtocols) {
|
||||||
ENET_ERROR("change protocol has not been accepted ... " << _data.getErrorCode() << " with message : " << _data.getHelp());
|
ENET_ERROR("change protocol has not been accepted ... " << _data.getErrorCode() << " with message : " << _data.getHelp());
|
||||||
m_interface->stop(true);
|
m_interface->stop(true);
|
||||||
@ -444,15 +473,10 @@ bool enet::WebSocket::configHeader(bool _isString, bool _mask) {
|
|||||||
m_sendBuffer.clear();
|
m_sendBuffer.clear();
|
||||||
m_sendBuffer.resize(ZEUS_BASE_OFFSET_HEADER, 0);
|
m_sendBuffer.resize(ZEUS_BASE_OFFSET_HEADER, 0);
|
||||||
if (_mask == true) {
|
if (_mask == true) {
|
||||||
std::random_device rd;
|
m_dataMask[0] = uint8_t(etk::tool::urand(0,255));
|
||||||
// Engine
|
m_dataMask[1] = uint8_t(etk::tool::urand(0,255));
|
||||||
std::mt19937 e2(rd());
|
m_dataMask[2] = uint8_t(etk::tool::urand(0,255));
|
||||||
// Distribtuions
|
m_dataMask[3] = uint8_t(etk::tool::urand(0,255));
|
||||||
std::uniform_real_distribution<> dist(0, 0xFF);
|
|
||||||
m_dataMask[0] = uint8_t(dist(e2));
|
|
||||||
m_dataMask[1] = uint8_t(dist(e2));
|
|
||||||
m_dataMask[2] = uint8_t(dist(e2));
|
|
||||||
m_dataMask[3] = uint8_t(dist(e2));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -465,7 +489,7 @@ int32_t enet::WebSocket::writeData(uint8_t* _data, int32_t _len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t enet::WebSocket::send() {
|
int32_t enet::WebSocket::send() {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -514,6 +538,7 @@ int32_t enet::WebSocket::send() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t enet::WebSocket::write(const void* _data, int32_t _len, bool _isString, bool _mask) {
|
int32_t enet::WebSocket::write(const void* _data, int32_t _len, bool _isString, bool _mask) {
|
||||||
|
ethread::UniqueLock lock(m_mutex);
|
||||||
if (configHeader(_isString, _mask) == false) {
|
if (configHeader(_isString, _mask) == false) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -522,39 +547,42 @@ int32_t enet::WebSocket::write(const void* _data, int32_t _len, bool _isString,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::controlPing() {
|
void enet::WebSocket::controlPing() {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ethread::UniqueLock lock(m_mutex);
|
||||||
uint8_t header = enet::websocket::FLAG_FIN
|
uint8_t header = enet::websocket::FLAG_FIN
|
||||||
| enet::websocket::OPCODE_FRAME_PING;
|
| enet::websocket::OPCODE_FRAME_PING;
|
||||||
m_lastSend = std::chrono::steady_clock::now();
|
m_lastSend = echrono::Steady::now();
|
||||||
m_interface->write(&header, sizeof(uint8_t));
|
m_interface->write(&header, sizeof(uint8_t));
|
||||||
header = 0;
|
header = 0;
|
||||||
m_interface->write(&header, sizeof(uint8_t));
|
m_interface->write(&header, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::controlPong() {
|
void enet::WebSocket::controlPong() {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ethread::UniqueLock lock(m_mutex);
|
||||||
uint8_t header = enet::websocket::FLAG_FIN
|
uint8_t header = enet::websocket::FLAG_FIN
|
||||||
| enet::websocket::OPCODE_FRAME_PONG;
|
| enet::websocket::OPCODE_FRAME_PONG;
|
||||||
m_lastSend = std::chrono::steady_clock::now();
|
m_lastSend = echrono::Steady::now();
|
||||||
m_interface->write(&header, sizeof(uint8_t));
|
m_interface->write(&header, sizeof(uint8_t));
|
||||||
header = 0;
|
header = 0;
|
||||||
m_interface->write(&header, sizeof(uint8_t));
|
m_interface->write(&header, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet::WebSocket::controlClose() {
|
void enet::WebSocket::controlClose() {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
ENET_ERROR("Nullptr interface ...");
|
ENET_ERROR("Nullptr interface ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ethread::UniqueLock lock(m_mutex);
|
||||||
uint8_t header = enet::websocket::FLAG_FIN
|
uint8_t header = enet::websocket::FLAG_FIN
|
||||||
| enet::websocket::OPCODE_FRAME_CLOSE;
|
| enet::websocket::OPCODE_FRAME_CLOSE;
|
||||||
m_lastSend = std::chrono::steady_clock::now();
|
m_lastSend = echrono::Steady::now();
|
||||||
m_interface->write(&header, sizeof(uint8_t));
|
m_interface->write(&header, sizeof(uint8_t));
|
||||||
header = 0;
|
header = 0;
|
||||||
m_interface->write(&header, sizeof(uint8_t));
|
m_interface->write(&header, sizeof(uint8_t));
|
||||||
|
@ -1,30 +1,33 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enet/Http.hpp>
|
#include <enet/Http.hpp>
|
||||||
#include <ememory/memory.hpp>
|
#include <ememory/memory.hpp>
|
||||||
#include <vector>
|
#include <echrono/Steady.hpp>
|
||||||
#include <map>
|
#include <etk/Vector.hpp>
|
||||||
|
#include <etk/Map.hpp>
|
||||||
|
|
||||||
namespace enet {
|
namespace enet {
|
||||||
class WebSocket {
|
class WebSocket {
|
||||||
protected:
|
protected:
|
||||||
std::vector<uint8_t> m_sendBuffer;
|
etk::Vector<uint8_t> m_sendBuffer;
|
||||||
bool m_connectionValidate;
|
bool m_connectionValidate;
|
||||||
ememory::SharedPtr<enet::Http> m_interface;
|
ememory::SharedPtr<enet::Http> m_interface;
|
||||||
std::vector<uint8_t> m_buffer;
|
etk::Vector<uint8_t> m_buffer;
|
||||||
std::string m_checkKey;
|
etk::String m_checkKey;
|
||||||
std::chrono::steady_clock::time_point m_lastReceive;
|
echrono::Steady m_lastReceive;
|
||||||
std::chrono::steady_clock::time_point m_lastSend;
|
echrono::Steady m_lastSend;
|
||||||
|
ethread::Mutex m_mutex;
|
||||||
|
bool m_redirectInProgress = false;
|
||||||
public:
|
public:
|
||||||
const std::chrono::steady_clock::time_point& getLastTimeReceive() {
|
const echrono::Steady& getLastTimeReceive() {
|
||||||
return m_lastReceive;
|
return m_lastReceive;
|
||||||
}
|
}
|
||||||
const std::chrono::steady_clock::time_point& getLastTimeSend() {
|
const echrono::Steady& getLastTimeSend() {
|
||||||
return m_lastSend;
|
return m_lastSend;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
@ -32,10 +35,10 @@ namespace enet {
|
|||||||
WebSocket(enet::Tcp _connection, bool _isServer=false);
|
WebSocket(enet::Tcp _connection, bool _isServer=false);
|
||||||
void setInterface(enet::Tcp _connection, bool _isServer=false);
|
void setInterface(enet::Tcp _connection, bool _isServer=false);
|
||||||
virtual ~WebSocket();
|
virtual ~WebSocket();
|
||||||
void start(const std::string& _uri="", const std::vector<std::string>& _listProtocols=std::vector<std::string>());
|
void start(const etk::String& _uri="", const etk::Vector<etk::String>& _listProtocols=etk::Vector<etk::String>());
|
||||||
void stop(bool _inThread=false);
|
void stop(bool _inThread=false);
|
||||||
bool isAlive() const {
|
bool isAlive() const {
|
||||||
if (m_interface == nullptr) {
|
if (m_interface == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_interface->isAlive();
|
return m_interface->isAlive();
|
||||||
@ -44,13 +47,19 @@ namespace enet {
|
|||||||
void onReceiveRequest(const enet::HttpRequest& _data);
|
void onReceiveRequest(const enet::HttpRequest& _data);
|
||||||
void onReceiveAnswer(const enet::HttpAnswer& _data);
|
void onReceiveAnswer(const enet::HttpAnswer& _data);
|
||||||
protected:
|
protected:
|
||||||
std::string m_protocol;
|
etk::String m_protocol;
|
||||||
public:
|
public:
|
||||||
void setProtocol(const std::string& _protocol) {
|
void setProtocol(const etk::String& _protocol) {
|
||||||
m_protocol = _protocol;
|
m_protocol = _protocol;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
using Observer = std::function<void(std::vector<uint8_t>&, bool)>; //!< Define an Observer: function pointer
|
/**
|
||||||
|
* @brief Get the address of the connection source IP:port or empty string
|
||||||
|
* @return string with the remote address name.
|
||||||
|
*/
|
||||||
|
const etk::String& getRemoteAddress() const;
|
||||||
|
public:
|
||||||
|
using Observer = etk::Function<void(etk::Vector<uint8_t>&, bool)>; //!< Define an Observer: function pointer
|
||||||
protected:
|
protected:
|
||||||
Observer m_observer;
|
Observer m_observer;
|
||||||
public:
|
public:
|
||||||
@ -61,8 +70,8 @@ namespace enet {
|
|||||||
* @param[in] _args Argument optinnal the user want to add.
|
* @param[in] _args Argument optinnal the user want to add.
|
||||||
*/
|
*/
|
||||||
template<class CLASS_TYPE>
|
template<class CLASS_TYPE>
|
||||||
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(std::vector<uint8_t>&, bool)) {
|
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(etk::Vector<uint8_t>&, bool)) {
|
||||||
m_observer = [=](std::vector<uint8_t>& _value, bool _isString){
|
m_observer = [=](etk::Vector<uint8_t>& _value, bool _isString){
|
||||||
(*_class.*_func)(_value, _isString);
|
(*_class.*_func)(_value, _isString);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -71,7 +80,15 @@ namespace enet {
|
|||||||
}
|
}
|
||||||
// Only server:
|
// Only server:
|
||||||
public:
|
public:
|
||||||
using ObserverUriCheck = std::function<bool(const std::string&, const std::vector<std::string>&)>; //!< Define an Observer: function pointer
|
/**
|
||||||
|
* @brief Define an Observer: function pointer
|
||||||
|
* @param[in] _uri Current HTTP URI
|
||||||
|
* @param[in] _protocols List of protocol requested
|
||||||
|
* @return "OK" Connection accepted ==> send header
|
||||||
|
* @return "CLOSE" Close the current connection: 404
|
||||||
|
* @return "REDIRECT:IP:port" Redirect at the specific IP and port
|
||||||
|
*/
|
||||||
|
using ObserverUriCheck = etk::Function<etk::String(const etk::String&, const etk::Vector<etk::String>&)>;
|
||||||
protected:
|
protected:
|
||||||
ObserverUriCheck m_observerUriCheck;
|
ObserverUriCheck m_observerUriCheck;
|
||||||
public:
|
public:
|
||||||
@ -82,8 +99,8 @@ namespace enet {
|
|||||||
* @param[in] _args Argument optinnal the user want to add.
|
* @param[in] _args Argument optinnal the user want to add.
|
||||||
*/
|
*/
|
||||||
template<class CLASS_TYPE>
|
template<class CLASS_TYPE>
|
||||||
void connectUri(CLASS_TYPE* _class, bool (CLASS_TYPE::*_func)(const std::string&, const std::vector<std::string>&)) {
|
void connectUri(CLASS_TYPE* _class, etk::String (CLASS_TYPE::*_func)(const etk::String&, const etk::Vector<etk::String>&)) {
|
||||||
m_observerUriCheck = [=](const std::string& _value, const std::vector<std::string>& _protocols){
|
m_observerUriCheck = [=](const etk::String& _value, const etk::Vector<etk::String>& _protocols){
|
||||||
return (*_class.*_func)(_value, _protocols);
|
return (*_class.*_func)(_value, _protocols);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -95,8 +112,20 @@ namespace enet {
|
|||||||
bool m_haveMask;
|
bool m_haveMask;
|
||||||
uint8_t m_dataMask[4];
|
uint8_t m_dataMask[4];
|
||||||
public:
|
public:
|
||||||
|
ethread::UniqueLock getScopeLock() {
|
||||||
|
return etk::move(ethread::UniqueLock(m_mutex));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Compose the local header inside a temporary buffer ==> must lock external to prevent multiple simultaneous access
|
||||||
|
*/
|
||||||
bool configHeader(bool _isString=false, bool _mask= false);
|
bool configHeader(bool _isString=false, bool _mask= false);
|
||||||
|
/**
|
||||||
|
* CWrite data in a temporary buffer ==> must lock external to prevent multiple simultaneous access
|
||||||
|
*/
|
||||||
int32_t writeData(uint8_t* _data, int32_t _len);
|
int32_t writeData(uint8_t* _data, int32_t _len);
|
||||||
|
/**
|
||||||
|
* Use temporary buffer to send it in the socket ==> must lock external to prevent multiple simultaneous access
|
||||||
|
*/
|
||||||
int32_t send();
|
int32_t send();
|
||||||
/**
|
/**
|
||||||
* @brief Write a chunk of data on the socket
|
* @brief Write a chunk of data on the socket
|
||||||
@ -104,8 +133,8 @@ namespace enet {
|
|||||||
* @param[in] _len Size that must be written socket
|
* @param[in] _len Size that must be written socket
|
||||||
* @return >0 byte size on the socket write
|
* @return >0 byte size on the socket write
|
||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
|
* @note: This function is locked ...
|
||||||
*/
|
*/
|
||||||
//TODO : ...
|
|
||||||
int32_t write(const void* _data, int32_t _len, bool _isString=false, bool _mask= false);
|
int32_t write(const void* _data, int32_t _len, bool _isString=false, bool _mask= false);
|
||||||
/**
|
/**
|
||||||
* @brief Write a chunk of data on the socket
|
* @brief Write a chunk of data on the socket
|
||||||
@ -114,7 +143,7 @@ namespace enet {
|
|||||||
* @return >0 byte size on the socket write
|
* @return >0 byte size on the socket write
|
||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
*/
|
*/
|
||||||
int32_t write(const std::string& _data, bool _writeBackSlashZero = true) {
|
int32_t write(const etk::String& _data, bool _writeBackSlashZero = true) {
|
||||||
if (_data.size() == 0) {
|
if (_data.size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -131,7 +160,7 @@ namespace enet {
|
|||||||
* @return -1 an error occured.
|
* @return -1 an error occured.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
int32_t write(const std::vector<T>& _data) {
|
int32_t write(const etk::Vector<T>& _data) {
|
||||||
if (_data.size() == 0) {
|
if (_data.size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#include <enet/enet.hpp>
|
#include <enet/enet.hpp>
|
||||||
#include <enet/debug.hpp>
|
#include <enet/debug.hpp>
|
||||||
@ -19,7 +19,7 @@ static bool& getInitSatatus() {
|
|||||||
|
|
||||||
void enet::init(int _argc, const char** _argv) {
|
void enet::init(int _argc, const char** _argv) {
|
||||||
for (int32_t iii=0; iii<_argc; ++iii) {
|
for (int32_t iii=0; iii<_argc; ++iii) {
|
||||||
std::string value = _argv[iii];
|
etk::String value = _argv[iii];
|
||||||
if (etk::start_with(value, "--enet") == true) {
|
if (etk::start_with(value, "--enet") == true) {
|
||||||
ENET_ERROR("Unknow parameter type: '" << value << "'");
|
ENET_ERROR("Unknow parameter type: '" << value << "'");
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
100
enet/pourcentEncoding.cpp
Normal file
100
enet/pourcentEncoding.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
|
* @license MPL v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
#include <enet/pourcentEncoding.hpp>
|
||||||
|
#include <enet/debug.hpp>
|
||||||
|
#include <etk/types.hpp>
|
||||||
|
#include <etk/String.hpp>
|
||||||
|
|
||||||
|
const etk::String hexData = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
etk::String enet::pourcentEncode(const etk::String& _data) {
|
||||||
|
etk::String out;
|
||||||
|
for (auto &it : _data) {
|
||||||
|
if ( (it >= 'a' && it <= 'z')
|
||||||
|
|| (it >= 'A' && it <= 'Z')
|
||||||
|
|| (it >= '0' && it <= '9')
|
||||||
|
|| it == '-'
|
||||||
|
|| it == '_'
|
||||||
|
|| it == '.'
|
||||||
|
|| it == '~') {
|
||||||
|
out += it;
|
||||||
|
} else {
|
||||||
|
out += "%";
|
||||||
|
out += hexData[(uint32_t(it)>>4)&0x0F];
|
||||||
|
out += hexData[uint32_t(it)&0x0F];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t convertStringHexToInt(const char _value) {
|
||||||
|
if (_value >= 'a' && _value <= 'z') {
|
||||||
|
return int32_t(_value) - int32_t('a') + 10;
|
||||||
|
}
|
||||||
|
if (_value >= 'A' && _value <= 'Z') {
|
||||||
|
return int32_t(_value) - int32_t('A') + 10;
|
||||||
|
}
|
||||||
|
if (_value >= '0' && _value <= '9') {
|
||||||
|
return int32_t(_value) - int32_t('0');
|
||||||
|
}
|
||||||
|
ENET_ERROR("Not a hexadecimal Value: '" << _value << "'");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
etk::String enet::pourcentDecode(const etk::String& _data) {
|
||||||
|
etk::String out;
|
||||||
|
for (size_t iii=0; iii<_data.size(); ++iii) {
|
||||||
|
auto it = _data[iii];
|
||||||
|
if (it == '%') {
|
||||||
|
if (iii+2 < _data.size()) {
|
||||||
|
auto val1 = convertStringHexToInt(_data[iii+1])<<4;
|
||||||
|
val1 += convertStringHexToInt(_data[iii+2]);
|
||||||
|
out += char(val1);
|
||||||
|
iii += 2;
|
||||||
|
} else {
|
||||||
|
ENET_ERROR("can not convert pourcent ==> input size error: '" << _data << "'");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out += it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
etk::String enet::pourcentUriEncode(const etk::Map<etk::String, etk::String>& _data) {
|
||||||
|
etk::String out;
|
||||||
|
for (auto &it: _data) {
|
||||||
|
if (out.empty() == false) {
|
||||||
|
out += "&";
|
||||||
|
}
|
||||||
|
out += enet::pourcentEncode(it.first);
|
||||||
|
if (it.second.empty() == false) {
|
||||||
|
out += "=";
|
||||||
|
out += enet::pourcentEncode(it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
etk::Map<etk::String, etk::String> enet::pourcentUriDecode(const etk::String& _data) {
|
||||||
|
etk::Map<etk::String, etk::String> out;
|
||||||
|
auto listElements = etk::split(_data, '&');
|
||||||
|
for (auto &it : listElements) {
|
||||||
|
if (it.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto offset = it.find('=');
|
||||||
|
if (offset == etk::String::npos) {
|
||||||
|
out.set(enet::pourcentDecode(it), "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out.set(enet::pourcentDecode(it.extract(0, offset)),
|
||||||
|
enet::pourcentDecode(it.extract(offset+1, etk::String::npos)));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
43
enet/pourcentEncoding.hpp
Normal file
43
enet/pourcentEncoding.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
|
* @license MPL v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <etk/String.hpp>
|
||||||
|
#include <etk/Map.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace enet {
|
||||||
|
/**
|
||||||
|
* @brief Encode a string with transform the unvalid char in %XX.
|
||||||
|
* @param[in] _data Raw string.
|
||||||
|
* @return Encoded string.
|
||||||
|
*/
|
||||||
|
etk::String pourcentEncode(const etk::String& _data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode a string with %XX with normal chars.
|
||||||
|
* @param[in] _data Encoded string.
|
||||||
|
* @return Raw string.
|
||||||
|
*/
|
||||||
|
etk::String pourcentDecode(const etk::String& _data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode a map of string with %XX and "&" between element and = between key and value.
|
||||||
|
* @param[in] _data Imput map to encode.
|
||||||
|
* @return Encoded string.
|
||||||
|
*/
|
||||||
|
etk::String pourcentUriEncode(const etk::Map<etk::String, etk::String>& _data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode a map of string with %XX and "&" between element and = between key and value.
|
||||||
|
* @param[in] _data Encoded string like AAA=333&RRR=333&RRR
|
||||||
|
* @return Te decoded map of values.
|
||||||
|
*/
|
||||||
|
etk::Map<etk::String, etk::String> pourcentUriDecode(const etk::String& _data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
13
license.txt
13
license.txt
@ -1,13 +0,0 @@
|
|||||||
Copyright enet Edouard DUPIN
|
|
||||||
|
|
||||||
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.
|
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ def get_desc():
|
|||||||
return "e-net TEST test software for enet"
|
return "e-net TEST test software for enet"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -28,7 +28,7 @@ def configure(target, my_module):
|
|||||||
my_module.add_path(".")
|
my_module.add_path(".")
|
||||||
my_module.add_depend([
|
my_module.add_depend([
|
||||||
'enet',
|
'enet',
|
||||||
'gtest',
|
'etest',
|
||||||
'test-debug'
|
'test-debug'
|
||||||
])
|
])
|
||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ def get_desc():
|
|||||||
return "e-net TEST test software for enet"
|
return "e-net TEST test software for enet"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -28,7 +28,7 @@ def configure(target, my_module):
|
|||||||
my_module.add_path(".")
|
my_module.add_path(".")
|
||||||
my_module.add_depend([
|
my_module.add_depend([
|
||||||
'enet',
|
'enet',
|
||||||
'gtest',
|
'etest',
|
||||||
'test-debug'
|
'test-debug'
|
||||||
])
|
])
|
||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ def get_desc():
|
|||||||
return "e-net TEST test software for enet"
|
return "e-net TEST test software for enet"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -28,7 +28,7 @@ def configure(target, my_module):
|
|||||||
my_module.add_path(".")
|
my_module.add_path(".")
|
||||||
my_module.add_depend([
|
my_module.add_depend([
|
||||||
'enet',
|
'enet',
|
||||||
'gtest',
|
'etest',
|
||||||
'test-debug'
|
'test-debug'
|
||||||
])
|
])
|
||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ def get_desc():
|
|||||||
return "e-net TEST test software for enet"
|
return "e-net TEST test software for enet"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -28,7 +28,7 @@ def configure(target, my_module):
|
|||||||
my_module.add_path(".")
|
my_module.add_path(".")
|
||||||
my_module.add_depend([
|
my_module.add_depend([
|
||||||
'enet',
|
'enet',
|
||||||
'gtest',
|
'etest',
|
||||||
'test-debug'
|
'test-debug'
|
||||||
])
|
])
|
||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ def get_desc():
|
|||||||
return "e-net TEST test software for enet"
|
return "e-net TEST test software for enet"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -28,7 +28,7 @@ def configure(target, my_module):
|
|||||||
my_module.add_path(".")
|
my_module.add_path(".")
|
||||||
my_module.add_depend([
|
my_module.add_depend([
|
||||||
'enet',
|
'enet',
|
||||||
'gtest',
|
'etest',
|
||||||
'test-debug'
|
'test-debug'
|
||||||
])
|
])
|
||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ def get_desc():
|
|||||||
return "e-net TEST test software for enet"
|
return "e-net TEST test software for enet"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -28,7 +28,7 @@ def configure(target, my_module):
|
|||||||
my_module.add_path(".")
|
my_module.add_path(".")
|
||||||
my_module.add_depend([
|
my_module.add_depend([
|
||||||
'enet',
|
'enet',
|
||||||
'gtest',
|
'etest',
|
||||||
'test-debug'
|
'test-debug'
|
||||||
])
|
])
|
||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
|
45
lutin_enet-test.py
Normal file
45
lutin_enet-test.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import realog.debug as debug
|
||||||
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
|
def get_type():
|
||||||
|
return "BINARY"
|
||||||
|
|
||||||
|
def get_sub_type():
|
||||||
|
return "TEST"
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "e-net TEST basic backend"
|
||||||
|
|
||||||
|
def get_licence():
|
||||||
|
return "MPL-2"
|
||||||
|
|
||||||
|
def get_compagny_type():
|
||||||
|
return "com"
|
||||||
|
|
||||||
|
def get_compagny_name():
|
||||||
|
return "atria-soft"
|
||||||
|
|
||||||
|
def get_maintainer():
|
||||||
|
return "authors.txt"
|
||||||
|
|
||||||
|
def configure(target, my_module):
|
||||||
|
my_module.add_path(".")
|
||||||
|
my_module.add_depend([
|
||||||
|
'enet',
|
||||||
|
'etest',
|
||||||
|
'test-debug'
|
||||||
|
])
|
||||||
|
my_module.add_src_file([
|
||||||
|
'test/main-test.cpp',
|
||||||
|
'test/main-unit-pourcentEncoding.cpp'
|
||||||
|
])
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import lutin.debug as debug
|
import realog.debug as debug
|
||||||
import lutin.tools as tools
|
import lutin.tools as tools
|
||||||
|
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ def get_desc():
|
|||||||
return "TCP/UDP/HTTP/FTP interface"
|
return "TCP/UDP/HTTP/FTP interface"
|
||||||
|
|
||||||
def get_licence():
|
def get_licence():
|
||||||
return "APACHE-2"
|
return "MPL-2"
|
||||||
|
|
||||||
def get_compagny_type():
|
def get_compagny_type():
|
||||||
return "com"
|
return "com"
|
||||||
@ -42,6 +42,7 @@ def configure(target, my_module):
|
|||||||
'enet/Http.cpp',
|
'enet/Http.cpp',
|
||||||
'enet/Ftp.cpp',
|
'enet/Ftp.cpp',
|
||||||
'enet/WebSocket.cpp',
|
'enet/WebSocket.cpp',
|
||||||
|
'enet/pourcentEncoding.cpp',
|
||||||
])
|
])
|
||||||
my_module.add_header_file([
|
my_module.add_header_file([
|
||||||
'enet/enet.hpp',
|
'enet/enet.hpp',
|
||||||
@ -53,6 +54,7 @@ def configure(target, my_module):
|
|||||||
'enet/Http.hpp',
|
'enet/Http.hpp',
|
||||||
'enet/Ftp.hpp',
|
'enet/Ftp.hpp',
|
||||||
'enet/WebSocket.hpp',
|
'enet/WebSocket.hpp',
|
||||||
|
'enet/pourcentEncoding.hpp',
|
||||||
])
|
])
|
||||||
if "Windows" in target.get_type():
|
if "Windows" in target.get_type():
|
||||||
my_module.add_depend("ws2");
|
my_module.add_depend("ws2");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test-debug/debug.hpp>
|
#include <test-debug/debug.hpp>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace appl {
|
namespace appl {
|
||||||
void onReceiveData(std::vector<uint8_t>& _data) {
|
void onReceiveData(etk::Vector<uint8_t>& _data) {
|
||||||
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
||||||
TEST_INFO("data:" << (char*)&_data[0] << "");
|
TEST_INFO("data:" << (char*)&_data[0] << "");
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
etk::init(_argc, _argv);
|
etk::init(_argc, _argv);
|
||||||
enet::init(_argc, _argv);
|
enet::init(_argc, _argv);
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||||
std::string data = _argv[iii];
|
etk::String data = _argv[iii];
|
||||||
if ( data == "-h"
|
if ( data == "-h"
|
||||||
|| data == "--help") {
|
|| data == "--help") {
|
||||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||||
@ -38,11 +38,11 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
TEST_INFO("== Test HTTP client ==");
|
TEST_INFO("== Test HTTP client ==");
|
||||||
TEST_INFO("==================================");
|
TEST_INFO("==================================");
|
||||||
// connect on TCP server:
|
// connect on TCP server:
|
||||||
enet::Tcp tcpConnection = std::move(enet::connectTcpClient("127.0.0.1", 12345));
|
enet::Tcp tcpConnection = etk::move(enet::connectTcpClient("127.0.0.1", 12345));
|
||||||
// TODO : Check if connection is valid ...
|
// TODO : Check if connection is valid ...
|
||||||
|
|
||||||
// Create a HTTP connection in Client mode
|
// Create a HTTP connection in Client mode
|
||||||
enet::HttpClient connection(std::move(tcpConnection));
|
enet::HttpClient connection(etk::move(tcpConnection));
|
||||||
// Set callbacks:
|
// Set callbacks:
|
||||||
connection.connect(appl::onReceiveData);
|
connection.connect(appl::onReceiveData);
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
connection.setHeader(req);
|
connection.setHeader(req);
|
||||||
|
|
||||||
while (connection.isAlive() == true) {
|
while (connection.isAlive() == true) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
ethread::sleepMilliSeconds((100));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test-debug/debug.hpp>
|
#include <test-debug/debug.hpp>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace appl {
|
namespace appl {
|
||||||
void onReceiveData(std::vector<uint8_t>& _data, bool _isString) {
|
void onReceiveData(etk::Vector<uint8_t>& _data, bool _isString) {
|
||||||
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
||||||
if (_isString == true) {
|
if (_isString == true) {
|
||||||
_data.resize(_data.size()+1);
|
_data.resize(_data.size()+1);
|
||||||
@ -32,7 +32,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
etk::init(_argc, _argv);
|
etk::init(_argc, _argv);
|
||||||
enet::init(_argc, _argv);
|
enet::init(_argc, _argv);
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||||
std::string data = _argv[iii];
|
etk::String data = _argv[iii];
|
||||||
if ( data == "-h"
|
if ( data == "-h"
|
||||||
|| data == "--help") {
|
|| data == "--help") {
|
||||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||||
@ -45,19 +45,19 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
TEST_INFO("== Test WebSocket client ==");
|
TEST_INFO("== Test WebSocket client ==");
|
||||||
TEST_INFO("==================================");
|
TEST_INFO("==================================");
|
||||||
// connect on TCP server:
|
// connect on TCP server:
|
||||||
enet::Tcp tcpConnection = std::move(enet::connectTcpClient("127.0.0.1", 12345));
|
enet::Tcp tcpConnection = etk::move(enet::connectTcpClient("127.0.0.1", 12345));
|
||||||
// TODO : Check if connection is valid ...
|
// TODO : Check if connection is valid ...
|
||||||
|
|
||||||
// Create a HTTP connection in Client mode
|
// Create a HTTP connection in Client mode
|
||||||
enet::WebSocket connection(std::move(tcpConnection), false);
|
enet::WebSocket connection(etk::move(tcpConnection), false);
|
||||||
// Set callbacks:
|
// Set callbacks:
|
||||||
connection.connect(appl::onReceiveData);
|
connection.connect(appl::onReceiveData);
|
||||||
|
|
||||||
// start http connection (the actual state is just TCP start ...)
|
// start http connection (the actual state is just TCP start ...)
|
||||||
std::vector<std::string> protocols;
|
etk::Vector<etk::String> protocols;
|
||||||
protocols.push_back("test1526/1.0");
|
protocols.pushBack("test1526/1.0");
|
||||||
protocols.push_back("test1526/1.5");
|
protocols.pushBack("test1526/1.5");
|
||||||
protocols.push_back("Hello");
|
protocols.pushBack("Hello");
|
||||||
connection.start("/plop.txt", protocols);
|
connection.start("/plop.txt", protocols);
|
||||||
|
|
||||||
// send some data to play ...
|
// send some data to play ...
|
||||||
@ -66,7 +66,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
int32_t timeout = 20;
|
int32_t timeout = 20;
|
||||||
while (connection.isAlive() == true
|
while (connection.isAlive() == true
|
||||||
&& timeout > 0) {
|
&& timeout > 0) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
ethread::sleepMilliSeconds((100));
|
||||||
timeout--;
|
timeout--;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test-debug/debug.hpp>
|
#include <test-debug/debug.hpp>
|
||||||
@ -10,14 +10,13 @@
|
|||||||
#include <enet/TcpClient.hpp>
|
#include <enet/TcpClient.hpp>
|
||||||
#include <enet/Http.hpp>
|
#include <enet/Http.hpp>
|
||||||
#include <etk/etk.hpp>
|
#include <etk/etk.hpp>
|
||||||
#include <iostream>
|
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
|
|
||||||
int main(int _argc, const char *_argv[]) {
|
int main(int _argc, const char *_argv[]) {
|
||||||
etk::init(_argc, _argv);
|
etk::init(_argc, _argv);
|
||||||
enet::init(_argc, _argv);
|
enet::init(_argc, _argv);
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||||
std::string data = _argv[iii];
|
etk::String data = _argv[iii];
|
||||||
if ( data == "-h"
|
if ( data == "-h"
|
||||||
|| data == "--help") {
|
|| data == "--help") {
|
||||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||||
@ -31,7 +30,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
TEST_INFO("==================================");
|
TEST_INFO("==================================");
|
||||||
// client mode ...
|
// client mode ...
|
||||||
// connect on TCP server:
|
// connect on TCP server:
|
||||||
enet::Tcp connection = std::move(enet::connectTcpClient("127.0.0.1", 12345));
|
enet::Tcp connection = etk::move(enet::connectTcpClient("127.0.0.1", 12345));
|
||||||
TEST_INFO("CLIENT connect ...");
|
TEST_INFO("CLIENT connect ...");
|
||||||
if (connection.getConnectionStatus() != enet::Tcp::status::link) {
|
if (connection.getConnectionStatus() != enet::Tcp::status::link) {
|
||||||
TEST_ERROR("can not link to the socket...");
|
TEST_ERROR("can not link to the socket...");
|
||||||
@ -45,7 +44,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
int32_t len = connection.read(data, 1024);
|
int32_t len = connection.read(data, 1024);
|
||||||
TEST_INFO("read len=" << len << " data='" << data << "'");
|
TEST_INFO("read len=" << len << " data='" << data << "'");
|
||||||
//if (data[len-1] == '2') {
|
//if (data[len-1] == '2') {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
|
ethread::sleepMilliSeconds((delay));
|
||||||
delay--;
|
delay--;
|
||||||
if (delay == 0) {
|
if (delay == 0) {
|
||||||
delay = 500;
|
delay = 500;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test-debug/debug.hpp>
|
#include <test-debug/debug.hpp>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
namespace appl {
|
namespace appl {
|
||||||
void onReceiveData(enet::HttpServer* _interface, std::vector<uint8_t>& _data) {
|
void onReceiveData(enet::HttpServer* _interface, etk::Vector<uint8_t>& _data) {
|
||||||
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
||||||
}
|
}
|
||||||
void onReceiveHeader(enet::HttpServer* _interface, const enet::HttpRequest& _data) {
|
void onReceiveHeader(enet::HttpServer* _interface, const enet::HttpRequest& _data) {
|
||||||
@ -23,8 +23,8 @@ namespace appl {
|
|||||||
if (_data.getType() == enet::HTTPReqType::HTTP_GET) {
|
if (_data.getType() == enet::HTTPReqType::HTTP_GET) {
|
||||||
if (_data.getUri() == "plop.txt") {
|
if (_data.getUri() == "plop.txt") {
|
||||||
enet::HttpAnswer answer(enet::HTTPAnswerCode::c200_ok);
|
enet::HttpAnswer answer(enet::HTTPAnswerCode::c200_ok);
|
||||||
std::string data = "<html><head></head></body>coucou</body></html>";
|
etk::String data = "<html><head></head></body>coucou</body></html>";
|
||||||
answer.setKey("Content-Length", etk::to_string(data.size()));
|
answer.setKey("Content-Length", etk::toString(data.size()));
|
||||||
_interface->setHeader(answer);
|
_interface->setHeader(answer);
|
||||||
_interface->write(data);
|
_interface->write(data);
|
||||||
_interface->stop(true);
|
_interface->stop(true);
|
||||||
@ -42,7 +42,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
etk::init(_argc, _argv);
|
etk::init(_argc, _argv);
|
||||||
enet::init(_argc, _argv);
|
enet::init(_argc, _argv);
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||||
std::string data = _argv[iii];
|
etk::String data = _argv[iii];
|
||||||
if ( data == "-h"
|
if ( data == "-h"
|
||||||
|| data == "--help") {
|
|| data == "--help") {
|
||||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||||
@ -62,16 +62,16 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
// Start listening ...
|
// Start listening ...
|
||||||
interface.link();
|
interface.link();
|
||||||
// Wait a new connection ..
|
// Wait a new connection ..
|
||||||
enet::Tcp tcpConnection = std::move(interface.waitNext());
|
enet::Tcp tcpConnection = etk::move(interface.waitNext());
|
||||||
// Free Connected port
|
// Free Connected port
|
||||||
interface.unlink();
|
interface.unlink();
|
||||||
// TODO : Check if connection is valid ...
|
// TODO : Check if connection is valid ...
|
||||||
|
|
||||||
// Create a HTTP connection in Server mode
|
// Create a HTTP connection in Server mode
|
||||||
enet::HttpServer connection(std::move(tcpConnection));
|
enet::HttpServer connection(etk::move(tcpConnection));
|
||||||
enet::HttpServer* tmp = &connection;
|
enet::HttpServer* tmp = &connection;
|
||||||
// Set callbacks:
|
// Set callbacks:
|
||||||
connection.connect([=](std::vector<uint8_t>& _value){
|
connection.connect([=](etk::Vector<uint8_t>& _value){
|
||||||
appl::onReceiveData(tmp, _value);
|
appl::onReceiveData(tmp, _value);
|
||||||
});
|
});
|
||||||
connection.connectHeader([=](const enet::HttpRequest& _value){
|
connection.connectHeader([=](const enet::HttpRequest& _value){
|
||||||
@ -82,7 +82,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
connection.start();
|
connection.start();
|
||||||
|
|
||||||
while (connection.isAlive() == true) {
|
while (connection.isAlive() == true) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
ethread::sleepMilliSeconds((100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -97,8 +97,8 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
|
|
||||||
TEST_INFO("----------------------------");
|
TEST_INFO("----------------------------");
|
||||||
TEST_INFO("POST data : ");
|
TEST_INFO("POST data : ");
|
||||||
std::map<std::string, std::string> values;
|
etk::Map<etk::String, etk::String> values;
|
||||||
values.insert(std::make_pair<std::string, std::string>("plop", "valuePlop"));
|
values.insert(etk::makePair<etk::String, etk::String>("plop", "valuePlop"));
|
||||||
if (connection.post("", values) == false) {
|
if (connection.post("", values) == false) {
|
||||||
TEST_ERROR("can not POST data...");
|
TEST_ERROR("can not POST data...");
|
||||||
return -1;
|
return -1;
|
||||||
@ -107,7 +107,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
|
|
||||||
TEST_INFO("----------------------------");
|
TEST_INFO("----------------------------");
|
||||||
TEST_INFO("POST xml : ");
|
TEST_INFO("POST xml : ");
|
||||||
if (connection.post("", "text/xml; charset=utf-8", "<plop><string>value1</string></plop>") == false) {
|
if (connection.post("", "text/xml; charset=utf-8", "<plop><etk/String.hpp>value1</string></plop>") == false) {
|
||||||
TEST_ERROR("can not POST XML data...");
|
TEST_ERROR("can not POST XML data...");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test-debug/debug.hpp>
|
#include <test-debug/debug.hpp>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include <etk/stdTools.hpp>
|
#include <etk/stdTools.hpp>
|
||||||
namespace appl {
|
namespace appl {
|
||||||
void onReceiveData(enet::WebSocket* _interface, std::vector<uint8_t>& _data, bool _isString) {
|
void onReceiveData(enet::WebSocket* _interface, etk::Vector<uint8_t>& _data, bool _isString) {
|
||||||
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
|
||||||
if (_isString == true) {
|
if (_isString == true) {
|
||||||
_data.resize(_data.size()+1);
|
_data.resize(_data.size()+1);
|
||||||
@ -26,7 +26,7 @@ namespace appl {
|
|||||||
TEST_INFO("binary data: ... ");
|
TEST_INFO("binary data: ... ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool onReceiveUri(enet::WebSocket* _interface, const std::string& _uri, const std::vector<std::string>& _protocols) {
|
bool onReceiveUri(enet::WebSocket* _interface, const etk::String& _uri, const etk::Vector<etk::String>& _protocols) {
|
||||||
TEST_INFO("Receive Header uri: " << _uri);
|
TEST_INFO("Receive Header uri: " << _uri);
|
||||||
for (auto &it : _protocols) {
|
for (auto &it : _protocols) {
|
||||||
if (it == "test1526/1.5") {
|
if (it == "test1526/1.5") {
|
||||||
@ -45,7 +45,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
etk::init(_argc, _argv);
|
etk::init(_argc, _argv);
|
||||||
enet::init(_argc, _argv);
|
enet::init(_argc, _argv);
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||||
std::string data = _argv[iii];
|
etk::String data = _argv[iii];
|
||||||
if ( data == "-h"
|
if ( data == "-h"
|
||||||
|| data == "--help") {
|
|| data == "--help") {
|
||||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||||
@ -65,19 +65,19 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
// Start listening ...
|
// Start listening ...
|
||||||
interface.link();
|
interface.link();
|
||||||
// Wait a new connection ..
|
// Wait a new connection ..
|
||||||
enet::Tcp tcpConnection = std::move(interface.waitNext());
|
enet::Tcp tcpConnection = etk::move(interface.waitNext());
|
||||||
// Free Connected port
|
// Free Connected port
|
||||||
interface.unlink();
|
interface.unlink();
|
||||||
// TODO : Check if connection is valid ...
|
// TODO : Check if connection is valid ...
|
||||||
|
|
||||||
// Create a HTTP connection in Server mode
|
// Create a HTTP connection in Server mode
|
||||||
enet::WebSocket connection(std::move(tcpConnection), true);
|
enet::WebSocket connection(etk::move(tcpConnection), true);
|
||||||
enet::WebSocket* tmp = &connection;
|
enet::WebSocket* tmp = &connection;
|
||||||
// Set callbacks:
|
// Set callbacks:
|
||||||
connection.connect([=](std::vector<uint8_t>& _value, bool _isString){
|
connection.connect([=](etk::Vector<uint8_t>& _value, bool _isString){
|
||||||
appl::onReceiveData(tmp, _value, _isString);
|
appl::onReceiveData(tmp, _value, _isString);
|
||||||
});
|
});
|
||||||
connection.connectUri([=](const std::string& _value, const std::vector<std::string>& _protocols){
|
connection.connectUri([=](const etk::String& _value, const etk::Vector<etk::String>& _protocols){
|
||||||
return appl::onReceiveUri(tmp, _value, _protocols);
|
return appl::onReceiveUri(tmp, _value, _protocols);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
connection.start();
|
connection.start();
|
||||||
|
|
||||||
while (connection.isAlive() == true) {
|
while (connection.isAlive() == true) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
ethread::sleepMilliSeconds((100));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license MPL v2.0 (see license file)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test-debug/debug.hpp>
|
#include <test-debug/debug.hpp>
|
||||||
@ -17,7 +17,7 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
etk::init(_argc, _argv);
|
etk::init(_argc, _argv);
|
||||||
enet::init(_argc, _argv);
|
enet::init(_argc, _argv);
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||||
std::string data = _argv[iii];
|
etk::String data = _argv[iii];
|
||||||
if ( data == "-h"
|
if ( data == "-h"
|
||||||
|| data == "--help") {
|
|| data == "--help") {
|
||||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||||
@ -37,13 +37,13 @@ int main(int _argc, const char *_argv[]) {
|
|||||||
// Start listening ...
|
// Start listening ...
|
||||||
interface.link();
|
interface.link();
|
||||||
// Wait a new connection ..
|
// Wait a new connection ..
|
||||||
enet::Tcp tcpConnection = std::move(interface.waitNext());
|
enet::Tcp tcpConnection = etk::move(interface.waitNext());
|
||||||
// Free Connected port
|
// Free Connected port
|
||||||
interface.unlink();
|
interface.unlink();
|
||||||
|
|
||||||
int32_t iii = 0;
|
int32_t iii = 0;
|
||||||
while (tcpConnection.getConnectionStatus() == enet::Tcp::status::link) {
|
while (tcpConnection.getConnectionStatus() == enet::Tcp::status::link) {
|
||||||
int32_t len = tcpConnection.write("plop" + etk::to_string(iii));
|
int32_t len = tcpConnection.write("plop" + etk::toString(iii));
|
||||||
TEST_INFO("write len=" << len);
|
TEST_INFO("write len=" << len);
|
||||||
char data[1024];
|
char data[1024];
|
||||||
len = tcpConnection.read(data, 1024);
|
len = tcpConnection.read(data, 1024);
|
||||||
|
18
test/main-test.cpp
Normal file
18
test/main-test.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||||
|
* @license MPL v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <etk/types.hpp>
|
||||||
|
#include <test-debug/debug.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <etest/etest.hpp>
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
// init test engine:
|
||||||
|
etest::init(argc, argv);
|
||||||
|
TEST_INFO("TEST ETK");
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
38
test/main-unit-pourcentEncoding.cpp
Normal file
38
test/main-unit-pourcentEncoding.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||||
|
* @license MPL v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <etk/types.hpp>
|
||||||
|
#include <test-debug/debug.hpp>
|
||||||
|
#include <etest/etest.hpp>
|
||||||
|
#include <enet/pourcentEncoding.hpp>
|
||||||
|
|
||||||
|
TEST(pourcentSerializer, stringEncode) {
|
||||||
|
EXPECT_EQ(enet::pourcentEncode("hello"), "hello");
|
||||||
|
EXPECT_EQ(enet::pourcentEncode("hello@plop plouf-_~"), "hello%40plop%20plouf-_~");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pourcentSerializer, stringDecode) {
|
||||||
|
EXPECT_EQ(enet::pourcentDecode("hello"), "hello");
|
||||||
|
EXPECT_EQ(enet::pourcentDecode("hello%40plop%20plouf-_~"), "hello@plop plouf-_~");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pourcentSerializer, mapEncode) {
|
||||||
|
etk::Map<etk::String, etk::String> data;
|
||||||
|
data.set("hello", "value1");
|
||||||
|
data.set("simpleKey", "");
|
||||||
|
data.set("special Key", "coucou");
|
||||||
|
data.set("email", "you@example.com");
|
||||||
|
EXPECT_EQ(enet::pourcentUriEncode(data), "email=you%40example.com&hello=value1&simpleKey&special%20Key=coucou");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pourcentSerializer, mapDecode) {
|
||||||
|
auto data = enet::pourcentUriDecode("hello=value1&simpleKey&special%20Key=coucou&email=you%40example.com");
|
||||||
|
EXPECT_EQ(data.size(), 4);
|
||||||
|
EXPECT_EQ(data["hello"], "value1");
|
||||||
|
EXPECT_EQ(data["simpleKey"], "");
|
||||||
|
EXPECT_EQ(data["special Key"], "coucou");
|
||||||
|
EXPECT_EQ(data["email"], "you@example.com");
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
0.4.0
|
1.0.0
|
Loading…
x
Reference in New Issue
Block a user