Compare commits

...

28 Commits

Author SHA1 Message Date
b6b31818aa [RELEASE] Release v1.0.0 2021-02-16 21:43:02 +01:00
681f65a6c4 [DEBUG] update new API of lutin log 2019-05-03 10:18:22 +02:00
540aab40d4 [DEV] space correction 2019-04-01 21:57:43 +02:00
79c20a74ea [DEV] update nullptr in null (specific etk) 2018-06-19 22:15:52 +02:00
1617790e48 [DEV] add querry element in the request 2018-04-13 00:09:31 +02:00
5e422227ab [DEV] add option header' 2018-04-11 22:53:19 +02:00
273982e7d3 [DEV] add pourcentage enoding for URI in HTTP 2018-04-04 23:10:58 +02:00
212731101e [DEBUG] correct multiple argument error 2017-11-07 10:17:56 +01:00
b6d77a7910 [DEV] update to the new ETK allocator wrapper 2017-10-21 19:05:21 +02:00
c653ed5b4b [DEV] set websocket support the reconnection to an other server after http rediredt event 2017-10-14 10:49:26 +02:00
6ec43d60ed [DEV] add the capability to the HTTP to reconnect on an other client socket (not availlable for server mode) 2017-10-14 10:48:31 +02:00
e6f2d8041b [DEV] add parse of the remote TCP connection name in Linux 2017-10-14 10:47:35 +02:00
34bd74c67f [DEV] add the remote name connected to the TCP element IP:port 2017-10-14 10:46:32 +02:00
19ab3637cf [DEV] add client connection with unique string IP:port 2017-10-14 10:45:25 +02:00
790c165268 [DEBUG] update new Map 2017-09-26 15:48:25 +02:00
cb097b3ce5 [DEV] continue removing STL 2017-09-14 00:59:21 +02:00
73c73ef1f5 [DEV] remove STL 2017-09-07 23:38:26 +02:00
29607a6d46 [DEV] continue removing stl 2017-08-28 00:04:49 +02:00
54a5b66436 [DEBUG] missing functionnal 2017-06-07 00:25:35 +00:00
d260646f29 [DEBUG] correct an init and check of error in HTTP 2017-04-28 21:21:25 +02:00
36e7081920 [DEV] try to stabilize interface TCP 2017-04-27 21:47:42 +02:00
63c9757a50 [DEBUG] correct some double sent in a socket 2017-02-07 21:23:41 +01:00
0f4bbb87f7 Change licence APACHE-2 to MPL-2 ==> force source redistribution and permit static link 2017-01-05 21:28:23 +01:00
65ff5fb439 [DEV] change Time type std::chrono to echrono 2017-01-04 22:22:25 +01:00
85c8aeaad8 [DEV] add log in error multiple frame 2016-12-15 21:00:31 +01:00
39660fae32 [DEBUG] correct the stop sequence 2016-12-08 21:01:37 +01:00
18a4b7f72b [DEV] simplify code 2016-11-21 21:56:55 +01:00
2911d1c411 [DEV] update dev tag version 2016-10-23 23:20:07 +02:00
41 changed files with 1440 additions and 480 deletions

373
LICENSE Normal file
View 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.

View File

@ -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,

View File

@ -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,

View File

@ -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>

View File

@ -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

View File

@ -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;
} }

View File

@ -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:

View File

@ -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

View File

@ -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;
} }

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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:

View File

@ -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>

View File

@ -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

View File

@ -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));

View File

@ -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;
} }

View File

@ -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>

View File

@ -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

View File

@ -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 << "'");
} }

View File

@ -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
View 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
View 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);
}

View File

@ -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.

View 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([

View 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([

View 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([

View 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([

View 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([

View 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
View 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

View 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
@ -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");

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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
View 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();
}

View 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");
}

View File

@ -1 +1 @@
0.4.0 1.0.0