Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
b6b31818aa | |||
681f65a6c4 | |||
540aab40d4 | |||
79c20a74ea | |||
1617790e48 | |||
5e422227ab | |||
273982e7d3 | |||
212731101e | |||
b6d77a7910 | |||
c653ed5b4b | |||
6ec43d60ed | |||
e6f2d8041b | |||
34bd74c67f | |||
19ab3637cf | |||
790c165268 | |||
cb097b3ce5 | |||
73c73ef1f5 | |||
29607a6d46 | |||
54a5b66436 | |||
d260646f29 | |||
36e7081920 | |||
63c9757a50 | |||
0f4bbb87f7 | |||
65ff5fb439 | |||
85c8aeaad8 | |||
39660fae32 | |||
18a4b7f72b | |||
2911d1c411 | |||
f6480ba8ad | |||
a5950ce0e7 | |||
6fa2ed2003 | |||
1d63f0188f | |||
9e0421a822 | |||
a979e33401 | |||
5cb8ea40e3 | |||
d89531189e | |||
975c124bd4 | |||
1571338fde | |||
739f70020b | |||
0933437748 |
86
.travis.yml
86
.travis.yml
@@ -1,11 +1,7 @@
|
||||
language:
|
||||
- cpp
|
||||
language: cpp
|
||||
|
||||
sudo: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
branches:
|
||||
only:
|
||||
@@ -18,37 +14,75 @@ addons:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.9
|
||||
- expect
|
||||
- binutils-mingw-w64-x86-64 # 64bit MinGW
|
||||
- gcc-mingw-w64-x86-64
|
||||
- g++-mingw-w64-x86-64
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: CONF=release BUILDER=gcc TARGET=Linux TAG=Linux COMPILATOR_OPTION="--compilator-version=4.9" GCOV=--gcov
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
env: CONF=debug BUILDER=clang TARGET=Linux
|
||||
compiler: clang
|
||||
- os: linux
|
||||
env: CONF=release BUILDER=gcc TARGET=Windows TAG=Mingw
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
- os: linux
|
||||
env: CONF=release BUILDER=gcc TARGET=Android TAG=Android DISABLE_PACKAGE=-p
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
env: CONF=release BUILDER=clang TARGET=MacOs TAG=MacOs
|
||||
compiler: clang
|
||||
- os: osx
|
||||
env: CONF=release BUILDER=clang TARGET=IOs TAG=IOs
|
||||
compiler: clang
|
||||
|
||||
|
||||
install:
|
||||
- cd ..
|
||||
- pip install --user lutin
|
||||
|
||||
env:
|
||||
- CONF=debug BOARD=Linux BUILDER=clang GCOV=
|
||||
- CONF=release BOARD=Linux BUILDER=clang GCOV=
|
||||
- CONF=debug BOARD=Linux BUILDER=gcc GCOV=
|
||||
- CONF=release BOARD=Linux BUILDER=gcc GCOV=
|
||||
- CONF=debug BOARD=Linux BUILDER=gcc GCOV=--gcov
|
||||
- if [ "$TAG" == "Android" ]; then
|
||||
git clone --depth 1 --branch master https://github.com/HeeroYui/android-download-tool;
|
||||
./android-download-tool/dl-android.sh;
|
||||
fi
|
||||
- git clone --depth 1 --branch master https://github.com/atria-soft/ci.git
|
||||
- cd -
|
||||
|
||||
before_script:
|
||||
- cd ..
|
||||
- wget http://atria-soft.com/ci/coverage_send.py
|
||||
- wget http://atria-soft.com/ci/test_send.py
|
||||
- wget http://atria-soft.com/ci/warning_send.py
|
||||
- git clone https://github.com/atria-soft/etk.git
|
||||
- git clone https://github.com/atria-soft/elog.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/ememory.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/echrono.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/algue.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/etk.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/ethread.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/generic-library/gtest-lutin.git --recursive
|
||||
- git clone https://github.com/generic-library/z-lutin.git --recursive
|
||||
- git clone https://github.com/generic-library/openssl-lutin.git --recursive
|
||||
- pwd
|
||||
- ls -l
|
||||
- if [ "$BUILDER" == "gcc" ]; then COMPILATOR_OPTION="--compilator-version=4.9"; else COMPILATOR_OPTION=""; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
export PATH=$PATH:/Users/travis/Library/Python/2.7/bin/;
|
||||
fi
|
||||
- ./ci/build_send.py --tag=$TAG --status=START;
|
||||
|
||||
script:
|
||||
- lutin -w -j4 -C -P -c $BUILDER $COMPILATOR_OPTION -m $CONF $GCOV -p enet-test
|
||||
script:
|
||||
- lutin -w -j4 -C -P -t$TARGET -c $BUILDER $COMPILATOR_OPTION $BUS -m $CONF $GCOV $DISABLE_PACKAGE enet-*; STATUS=$?
|
||||
- ./ci/build_send.py --tag=$TAG --status="$STATUS";
|
||||
|
||||
after_script:
|
||||
- if [ "$GCOV" != "" ]; then python ./warning_send.py --find-path ./out/Linux_x86_64/$CONF/build/$BUILDER/enet/ ; fi
|
||||
- ./out/Linux_x86_64/$CONF/staging/$BUILDER/enet-test/usr/bin/enet-test -l6 | tee out_test.txt
|
||||
- if [ "$GCOV" != "" ]; then python ./test_send.py --file=out_test.txt; fi
|
||||
- if [ "$GCOV" != "" ]; then lutin -C -P -c $BUILDER $COMPILATOR_OPTION -m $CONF -p enet?gcov; fi
|
||||
- if [ "$GCOV" != "" ]; then python ./coverage_send.py --json=out/Linux_x86_64/$CONF/build/$BUILDER/enet/enet_coverage.json; fi
|
||||
- if [ "$GCOV" != "" ]; then
|
||||
./ci/warning_send.py --find-path ./out/Linux_x86_64/$CONF/build/$BUILDER/enet/;
|
||||
fi
|
||||
- lutin -w -j4 -C -P -t$TARGET -c $BUILDER $COMPILATOR_OPTION $BUS -m $CONF $GCOV $DISABLE_PACKAGE enet-test-client-websocket?run:--elog-level=3 | tee out_test.txt
|
||||
- if [ "$GCOV" != "" ]; then
|
||||
./ci/test_send.py --file=out_test.txt;
|
||||
lutin -C -P -t $TARGET -c $BUILDER $COMPILATOR_OPTION $BUS -m $CONF -p enet?gcov;
|
||||
./ci/coverage_send.py --json=out/Linux_x86_64/$CONF/build/$BUILDER/enet/enet_coverage.json;
|
||||
fi
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
373
LICENSE
Normal file
373
LICENSE
Normal file
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
63
README.md
63
README.md
@@ -3,28 +3,77 @@ enet
|
||||
|
||||
`enet` is a network abstraction layer for ewol
|
||||
|
||||
Release (master)
|
||||
----------------
|
||||
|
||||
[](https://travis-ci.org/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
Developement (dev)
|
||||
------------------
|
||||
|
||||
[](https://travis-ci.org/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
[](http://atria-soft.com/ci/atria-soft/enet)
|
||||
|
||||
|
||||
Instructions
|
||||
============
|
||||
|
||||
To compile and use see 'ewol' or 'edn' project
|
||||
download Build system:
|
||||
----------------------
|
||||
|
||||
License (APACHE v2.0)
|
||||
sudo pip install lutin
|
||||
sudo pip install pillow
|
||||
|
||||
download the software:
|
||||
----------------------
|
||||
|
||||
mkdir WORKING_DIRECTORY
|
||||
cd WORKING_DIRECTORY
|
||||
git clone https://github.com/atria-soft/elog.git
|
||||
git clone https://github.com/atria-soft/ememory.git
|
||||
git clone https://github.com/atria-soft/echrono.git
|
||||
git clone https://github.com/atria-soft/algue.git
|
||||
git clone https://github.com/atria-soft/etk.git
|
||||
git clone https://github.com/atria-soft/enet.git
|
||||
git clone https://github.com/generic-library/gtest-lutin.git --recursive
|
||||
git clone https://github.com/generic-library/z-lutin.git --recursive
|
||||
git clone https://github.com/generic-library/openssl-lutin.git --recursive
|
||||
|
||||
Compile software:
|
||||
-----------------
|
||||
|
||||
cd WORKING_DIRECTORY
|
||||
lutin -C -P enet-test?build?run
|
||||
|
||||
|
||||
License (MPL v2.0)
|
||||
=====================
|
||||
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 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
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
76
doc/build.md
Normal file
76
doc/build.md
Normal file
@@ -0,0 +1,76 @@
|
||||
Build lib & build sample {#enet_build}
|
||||
========================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
Download: {#enet_build_download}
|
||||
=========
|
||||
|
||||
enet use some tools to manage source and build it:
|
||||
|
||||
lutin (build-system): {#enet_build_download_lutin}
|
||||
---------------------
|
||||
|
||||
```{.sh}
|
||||
pip install lutin --user
|
||||
# optionnal dependency of lutin (manage image changing size for application release)
|
||||
pip install pillow --user
|
||||
```
|
||||
|
||||
|
||||
dependency: {#enet_build_download_dependency}
|
||||
-----------
|
||||
|
||||
```{.sh}
|
||||
mkdir framework
|
||||
cd framework
|
||||
git clone https://github.com/atria-soft/etk.git
|
||||
git clone https://github.com/atria-soft/ememory.git
|
||||
git clone https://github.com/atria-soft/algue.git
|
||||
git clone https://github.com/generic-library/gtest-lutin.git --recursive
|
||||
git clone https://github.com/generic-library/z-lutin.git --recursive
|
||||
git clone https://github.com/generic-library/openssl-lutin.git --recursive
|
||||
cd ..
|
||||
```
|
||||
|
||||
sources: {#enet_build_download_sources}
|
||||
--------
|
||||
|
||||
```{.sh}
|
||||
cd framework
|
||||
git clone https://github.com/atria-soft/enet.git
|
||||
cd ..
|
||||
```
|
||||
|
||||
Build: {#enet_build_build}
|
||||
======
|
||||
|
||||
|
||||
library: {#enet_build_build_library}
|
||||
--------
|
||||
|
||||
```{.sh}
|
||||
lutin -mdebug enet
|
||||
```
|
||||
|
||||
Sample: {#enet_build_build_sample}
|
||||
-------
|
||||
|
||||
```{.sh}
|
||||
lutin -mdebug enet-server-websocket enet-client-websocket
|
||||
```
|
||||
|
||||
|
||||
Run sample: {#enet_build_run_sample}
|
||||
===========
|
||||
|
||||
```{.sh}
|
||||
lutin -mdebug enet-server-websocket?run
|
||||
```
|
||||
|
||||
In an other bash:
|
||||
|
||||
```{.sh}
|
||||
lutin -mdebug enet-client-websocket?run
|
||||
```
|
||||
|
64
doc/mainpage.md
Normal file
64
doc/mainpage.md
Normal file
@@ -0,0 +1,64 @@
|
||||
ENET library {#mainpage}
|
||||
=============
|
||||
|
||||
@tableofcontents
|
||||
|
||||
What is ENET: {#enet_mainpage_what}
|
||||
==============
|
||||
|
||||
`enet` is a network abstraction layer for ewol
|
||||
|
||||
What it does: {#enet_mainpage_what_it_does}
|
||||
-------------
|
||||
|
||||
Provide some acces on Network interface for all platform (simplify API)
|
||||
|
||||
ENET is dependent of the STL (compatible with MacOs stl (CXX))
|
||||
|
||||
It provide some simple interface for TCP, HTTP, webSocket in server and client modes
|
||||
|
||||
|
||||
What is the TODO list: {#enet_mainpage_todo}
|
||||
----------------------
|
||||
|
||||
Create a full complient interface for every protocol ...
|
||||
|
||||
this is in dev
|
||||
|
||||
|
||||
What languages are supported? {#enet_mainpage_language}
|
||||
=============================
|
||||
|
||||
ENET is written in C++.
|
||||
|
||||
|
||||
Are there any licensing restrictions? {#enet_mainpage_license_restriction}
|
||||
=====================================
|
||||
|
||||
ENET is **FREE software** and _all sub-library are FREE and staticly linkable !!!_
|
||||
|
||||
|
||||
License (MPL v2.0) {#enet_mainpage_license}
|
||||
==================
|
||||
|
||||
Copyright ENET Edouard DUPIN
|
||||
|
||||
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 obtain a copy of the License at
|
||||
|
||||
<https://www.mozilla.org/MPL/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.
|
||||
|
||||
|
||||
Other pages {#enet_mainpage_sub_page}
|
||||
===========
|
||||
|
||||
- @ref enet_build
|
||||
- [**ewol coding style**](http://atria-soft.github.io/ewol/ewol_coding_style.html)
|
||||
|
33
doxy_enet.py
Normal file
33
doxy_enet.py
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import doxy.module as module
|
||||
import doxy.debug as debug
|
||||
import doxy.tools as tools
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name)
|
||||
my_module.set_version("version.txt")
|
||||
my_module.set_title("enet: Ewol network abstraction")
|
||||
my_module.set_website("http://atria-soft.github.io/" + module_name)
|
||||
my_module.set_website_sources("http://github.com/atria-soft/" + module_name)
|
||||
my_module.add_path([
|
||||
module_name,
|
||||
"doc"
|
||||
])
|
||||
my_module.add_depend([
|
||||
'etk',
|
||||
'ememory',
|
||||
#'algue'
|
||||
])
|
||||
my_module.add_exclude_symbols([
|
||||
'*operator<<*',
|
||||
])
|
||||
my_module.add_exclude_file([
|
||||
'debug.hpp',
|
||||
])
|
||||
my_module.add_file_patterns([
|
||||
'*.hpp',
|
||||
'*.md',
|
||||
])
|
||||
|
||||
return my_module
|
@@ -1,9 +1,8 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/Ftp.h>
|
||||
#include <string.h>
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/Ftp.hpp>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
403
enet/Http.cpp
403
enet/Http.cpp
@@ -1,24 +1,29 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/Http.h>
|
||||
#include <map>
|
||||
#include <etk/stdTools.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <etk/Map.hpp>
|
||||
#include <etk/Stream.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
#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;
|
||||
}
|
||||
static std::string unEscapeChar(const std::string& _value) {
|
||||
static etk::String unEscapeChar(const etk::String& _value) {
|
||||
return _value;
|
||||
}
|
||||
static std::string removeStartAndStopSpace(const std::string& _value) {
|
||||
std::string out;
|
||||
static etk::String removeStartAndStopSpace(const etk::String& _value) {
|
||||
etk::String out;
|
||||
out.reserve(_value.size());
|
||||
bool findSpace = false;
|
||||
for (auto &it : _value) {
|
||||
@@ -36,64 +41,71 @@ static std::string removeStartAndStopSpace(const std::string& _value) {
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::map<enet::HTTPAnswerCode, std::string> protocolName = {
|
||||
{enet::HTTPAnswerCode::c100_continue, "Continue"},
|
||||
{enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols"},
|
||||
{enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint"},
|
||||
{enet::HTTPAnswerCode::c200_ok, "OK"},
|
||||
{enet::HTTPAnswerCode::c201_created, "Created"},
|
||||
{enet::HTTPAnswerCode::c202_accepted, "Accepted"},
|
||||
{enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information"},
|
||||
{enet::HTTPAnswerCode::c204_noContent, "No Content"},
|
||||
{enet::HTTPAnswerCode::c205_resetContent, "Reset Content"},
|
||||
{enet::HTTPAnswerCode::c206_partialContent, "Partial Content"},
|
||||
{enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices"},
|
||||
{enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently"},
|
||||
{enet::HTTPAnswerCode::c302_found, "Found"},
|
||||
{enet::HTTPAnswerCode::c303_seeOther, "See Other"},
|
||||
{enet::HTTPAnswerCode::c304_notModified, "Not Modified"},
|
||||
{enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy"},
|
||||
{enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect"},
|
||||
{enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete"},
|
||||
{enet::HTTPAnswerCode::c400_badRequest, "Bad Request"},
|
||||
{enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized"},
|
||||
{enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required"},
|
||||
{enet::HTTPAnswerCode::c403_forbidden, "Forbidden"},
|
||||
{enet::HTTPAnswerCode::c404_notFound, "Not Found"},
|
||||
{enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed"},
|
||||
{enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable"},
|
||||
{enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required"},
|
||||
{enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout"},
|
||||
{enet::HTTPAnswerCode::c409_conflict, "Conflict"},
|
||||
{enet::HTTPAnswerCode::c410_gone, "Gone"},
|
||||
{enet::HTTPAnswerCode::c411_lengthRequired, "Length Required"},
|
||||
{enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed"},
|
||||
{enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large"},
|
||||
{enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long"},
|
||||
{enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type"},
|
||||
{enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable"},
|
||||
{enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed"},
|
||||
{enet::HTTPAnswerCode::c500_internalServerError, "Internal Server Error"},
|
||||
{enet::HTTPAnswerCode::c501_notImplemented, "Not Implemented"},
|
||||
{enet::HTTPAnswerCode::c502_badGateway, "Bad Gateway"},
|
||||
{enet::HTTPAnswerCode::c503_serviceUnavailable, "Service Unavailable"},
|
||||
{enet::HTTPAnswerCode::c504_gatewayTimeout, "Gateway Timeout"},
|
||||
{enet::HTTPAnswerCode::c505_httpVersionNotSupported, "HTTP Version Not Supported"},
|
||||
{enet::HTTPAnswerCode::c511_networkAuthenticationRequired, "Network Authentication Required"}
|
||||
static const etk::Map<enet::HTTPAnswerCode, etk::String>& getProtocolName() {
|
||||
static etk::Map<enet::HTTPAnswerCode, etk::String> protocolName;
|
||||
static bool isInit = false;
|
||||
if (isInit == true) {
|
||||
return protocolName;
|
||||
}
|
||||
isInit = true;
|
||||
protocolName.add(enet::HTTPAnswerCode::c100_continue, "Continue");
|
||||
protocolName.add(enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols");
|
||||
protocolName.add(enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint");
|
||||
protocolName.add(enet::HTTPAnswerCode::c200_ok, "OK");
|
||||
protocolName.add(enet::HTTPAnswerCode::c201_created, "Created");
|
||||
protocolName.add(enet::HTTPAnswerCode::c202_accepted, "Accepted");
|
||||
protocolName.add(enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information");
|
||||
protocolName.add(enet::HTTPAnswerCode::c204_noContent, "No Content");
|
||||
protocolName.add(enet::HTTPAnswerCode::c205_resetContent, "Reset Content");
|
||||
protocolName.add(enet::HTTPAnswerCode::c206_partialContent, "Partial Content");
|
||||
protocolName.add(enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices");
|
||||
protocolName.add(enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently");
|
||||
protocolName.add(enet::HTTPAnswerCode::c302_found, "Found");
|
||||
protocolName.add(enet::HTTPAnswerCode::c303_seeOther, "See Other");
|
||||
protocolName.add(enet::HTTPAnswerCode::c304_notModified, "Not Modified");
|
||||
protocolName.add(enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy");
|
||||
protocolName.add(enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect");
|
||||
protocolName.add(enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete");
|
||||
protocolName.add(enet::HTTPAnswerCode::c400_badRequest, "Bad Request");
|
||||
protocolName.add(enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized");
|
||||
protocolName.add(enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required");
|
||||
protocolName.add(enet::HTTPAnswerCode::c403_forbidden, "Forbidden");
|
||||
protocolName.add(enet::HTTPAnswerCode::c404_notFound, "Not Found");
|
||||
protocolName.add(enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed");
|
||||
protocolName.add(enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable");
|
||||
protocolName.add(enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required");
|
||||
protocolName.add(enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout");
|
||||
protocolName.add(enet::HTTPAnswerCode::c409_conflict, "Conflict");
|
||||
protocolName.add(enet::HTTPAnswerCode::c410_gone, "Gone");
|
||||
protocolName.add(enet::HTTPAnswerCode::c411_lengthRequired, "Length Required");
|
||||
protocolName.add(enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed");
|
||||
protocolName.add(enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large");
|
||||
protocolName.add(enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long");
|
||||
protocolName.add(enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type");
|
||||
protocolName.add(enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable");
|
||||
protocolName.add(enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed");
|
||||
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 std::map<int32_t, std::string> g_list;
|
||||
static etk::Map<int32_t, etk::String> getErrorList() {
|
||||
static etk::Map<int32_t, etk::String> g_list;
|
||||
return g_list;
|
||||
}
|
||||
|
||||
enet::Http::Http(enet::Tcp _connection, bool _isServer) :
|
||||
m_isServer(_isServer),
|
||||
m_connection(std::move(_connection)),
|
||||
m_connection(etk::move(_connection)),
|
||||
m_headerIsSend(false),
|
||||
m_thread(nullptr),
|
||||
m_thread(null),
|
||||
m_threadRunning(false) {
|
||||
//setSendHeaderProperties("User-Agent", "e-net (ewol network interface)");
|
||||
/*
|
||||
@@ -116,16 +128,18 @@ void enet::Http::threadCallback() {
|
||||
// READ section data:
|
||||
if (m_headerIsSend == false) {
|
||||
getHeader();
|
||||
m_headerIsSend = true;
|
||||
if (m_headerIsSend == false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (m_observerRaw != nullptr) {
|
||||
if (m_observerRaw != null) {
|
||||
m_observerRaw(m_connection);
|
||||
} else {
|
||||
m_temporaryBuffer.resize(67000);
|
||||
int32_t len = m_connection.read(&m_temporaryBuffer[0], m_temporaryBuffer.size());
|
||||
if (len > 0) {
|
||||
ENET_INFO("Call client with datas ...");
|
||||
if (m_observer != nullptr) {
|
||||
if (m_observer != null) {
|
||||
m_observer(m_temporaryBuffer);
|
||||
}
|
||||
}
|
||||
@@ -135,19 +149,28 @@ void enet::Http::threadCallback() {
|
||||
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() {
|
||||
ENET_DEBUG("connect [START]");
|
||||
m_threadRunning = true;
|
||||
m_thread = new std::thread([&](void *){ this->threadCallback();}, nullptr);
|
||||
if (m_thread == nullptr) {
|
||||
m_thread = ETK_NEW(ethread::Thread, [&](){ threadCallback();});
|
||||
if (m_thread == null) {
|
||||
m_threadRunning = false;
|
||||
ENET_ERROR("creating callback thread!");
|
||||
return;
|
||||
}
|
||||
while ( m_threadRunning == true
|
||||
&& m_connection.getConnectionStatus() != enet::Tcp::status::link) {
|
||||
usleep(50000);
|
||||
ethread::sleepMilliSeconds((50));
|
||||
}
|
||||
//ethread::setPriority(*m_receiveThread, -6);
|
||||
ENET_DEBUG("connect [STOP]");
|
||||
@@ -166,21 +189,23 @@ void enet::Http::stop(bool _inThreadStop){
|
||||
m_connection.unlink();
|
||||
}
|
||||
if (_inThreadStop == false) {
|
||||
if (m_thread != nullptr) {
|
||||
if (m_thread != null) {
|
||||
ENET_DEBUG("wait join Thread ...");
|
||||
m_thread->join();
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
ENET_DEBUG("wait join Thread (done)");
|
||||
ETK_DELETE(ethread::Thread, m_thread);
|
||||
m_thread = null;
|
||||
}
|
||||
}
|
||||
ENET_DEBUG("disconnect [STOP]");
|
||||
}
|
||||
/*
|
||||
void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
|
||||
std::string out;
|
||||
etk::String out;
|
||||
out = "HTTP/1.1 ";
|
||||
out += etk::to_string(int32_t(_value));
|
||||
auto it = protocolName.find(_value);
|
||||
if (it == protocolName.end() ) {
|
||||
out += etk::toString(int32_t(_value));
|
||||
auto it = getProtocolName().find(_value);
|
||||
if (it == getProtocolName().end() ) {
|
||||
out += " ???";
|
||||
} else {
|
||||
out += " " + it->second;
|
||||
@@ -192,10 +217,10 @@ void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
|
||||
*/
|
||||
namespace etk {
|
||||
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;
|
||||
for (auto &it : protocolName) {
|
||||
if (etk::to_string(int32_t(it.first)) == _value) {
|
||||
for (auto &it : getProtocolName()) {
|
||||
if (etk::toString(int32_t(it.first)) == _value) {
|
||||
_variableRet = it.first;
|
||||
return true;
|
||||
}
|
||||
@@ -203,43 +228,47 @@ namespace etk {
|
||||
return false;
|
||||
}
|
||||
template <>
|
||||
std::string to_string<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
|
||||
return etk::to_string(int32_t(_value));
|
||||
etk::String toString<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
|
||||
return etk::toString(int32_t(_value));
|
||||
}
|
||||
template <>
|
||||
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const std::string& _value) {
|
||||
_variableRet = enet::HTTPReqType::GET;
|
||||
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const etk::String& _value) {
|
||||
_variableRet = enet::HTTPReqType::HTTP_GET;
|
||||
if (_value == "GET") {
|
||||
_variableRet = enet::HTTPReqType::GET;
|
||||
_variableRet = enet::HTTPReqType::HTTP_GET;
|
||||
return true;
|
||||
} else if (_value == "HEAD") {
|
||||
_variableRet = enet::HTTPReqType::HEAD;
|
||||
_variableRet = enet::HTTPReqType::HTTP_HEAD;
|
||||
return true;
|
||||
} else if (_value == "POST") {
|
||||
_variableRet = enet::HTTPReqType::POST;
|
||||
_variableRet = enet::HTTPReqType::HTTP_POST;
|
||||
return true;
|
||||
} else if (_value == "PUT") {
|
||||
_variableRet = enet::HTTPReqType::PUT;
|
||||
_variableRet = enet::HTTPReqType::HTTP_PUT;
|
||||
return true;
|
||||
} else if (_value == "DELETE") {
|
||||
_variableRet = enet::HTTPReqType::DELETE;
|
||||
_variableRet = enet::HTTPReqType::HTTP_DELETE;
|
||||
return true;
|
||||
} else if (_value == "OPTIONS") {
|
||||
_variableRet = enet::HTTPReqType::HTTP_OPTIONS;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
case enet::HTTPReqType::GET: return "GET";
|
||||
case enet::HTTPReqType::HEAD: return "HEAD";
|
||||
case enet::HTTPReqType::POST: return "POST";
|
||||
case enet::HTTPReqType::PUT: return "PUT";
|
||||
case enet::HTTPReqType::DELETE: return "DELETE";
|
||||
case enet::HTTPReqType::HTTP_GET: return "GET";
|
||||
case enet::HTTPReqType::HTTP_HEAD: return "HEAD";
|
||||
case enet::HTTPReqType::HTTP_POST: return "POST";
|
||||
case enet::HTTPReqType::HTTP_PUT: return "PUT";
|
||||
case enet::HTTPReqType::HTTP_DELETE: return "DELETE";
|
||||
case enet::HTTPReqType::HTTP_OPTIONS: return "OPTIONS";
|
||||
}
|
||||
return "UNKNOW";
|
||||
}
|
||||
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;
|
||||
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; }
|
||||
@@ -287,7 +316,7 @@ namespace etk {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
case enet::HTTPProtocol::http_0_1: return "HTTP/0.1";
|
||||
case enet::HTTPProtocol::http_0_2: return "HTTP/0.2";
|
||||
@@ -340,31 +369,43 @@ namespace etk {
|
||||
|
||||
void enet::Http::setRequestHeader(const enet::HttpRequest& _req) {
|
||||
m_requestHeader = _req;
|
||||
if (m_requestHeader.getKey("User-Agent") == "") {
|
||||
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
|
||||
if (m_isServer == true) {
|
||||
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);
|
||||
}
|
||||
|
||||
void enet::Http::setAnswerHeader(const enet::HttpAnswer& _req) {
|
||||
m_answerHeader = _req;
|
||||
if (m_requestHeader.getKey("User-Agent") == "") {
|
||||
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
|
||||
if (m_isServer == true) {
|
||||
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);
|
||||
}
|
||||
|
||||
void enet::Http::getHeader() {
|
||||
ENET_VERBOSE("Read HTTP Header [START]");
|
||||
bool headerEnded = false;
|
||||
std::string header;
|
||||
etk::String header;
|
||||
while (m_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
||||
char type;
|
||||
char type = '?';
|
||||
int32_t len = m_connection.read(&type, 1);
|
||||
if (len == 0) {
|
||||
usleep(1);
|
||||
ethread::sleepMilliSeconds(1);
|
||||
continue;
|
||||
}
|
||||
header += type;
|
||||
@@ -394,7 +435,7 @@ void enet::Http::getHeader() {
|
||||
ENET_VERBOSE("Read HTTP Header [STOP] : '" << header << "'");
|
||||
m_headerIsSend = true;
|
||||
// parse header :
|
||||
std::vector<std::string> list = etk::split(header, '\n');
|
||||
etk::Vector<etk::String> list = etk::split(header, '\n');
|
||||
for (auto &it : list) {
|
||||
if ( it.size()>0
|
||||
&& it[it.size()-1] == '\r') {
|
||||
@@ -402,7 +443,7 @@ void enet::Http::getHeader() {
|
||||
}
|
||||
}
|
||||
//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) {
|
||||
ENET_ERROR("can not parse answear : " << listLineOne);
|
||||
// answer bad request and close connection ...
|
||||
@@ -414,7 +455,8 @@ void enet::Http::getHeader() {
|
||||
|| listLineOne[0] == "POST"
|
||||
|| listLineOne[0] == "HEAD"
|
||||
|| listLineOne[0] == "DELETE"
|
||||
|| listLineOne[0] == "PUT" ) ) {
|
||||
|| listLineOne[0] == "PUT"
|
||||
|| listLineOne[0] == "OPTIONS" ) ) {
|
||||
// HTTP CALL
|
||||
if (m_isServer == false) {
|
||||
// can not have call in client mode
|
||||
@@ -430,7 +472,14 @@ void enet::Http::getHeader() {
|
||||
etk::from_string(valueType, listLineOne[0]);
|
||||
m_requestHeader.setType(valueType);
|
||||
// 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:
|
||||
enum enet::HTTPProtocol valueProtocol;
|
||||
etk::from_string(valueProtocol, listLineOne[2]);
|
||||
@@ -457,7 +506,7 @@ void enet::Http::getHeader() {
|
||||
m_answerHeader.setErrorCode(valueErrorCode);
|
||||
|
||||
// get comment:
|
||||
std::string comment;
|
||||
etk::String comment;
|
||||
for (size_t iii=2; iii<listLineOne.size(); ++iii) {
|
||||
if (comment.size() != 0) {
|
||||
comment += " ";
|
||||
@@ -476,13 +525,13 @@ void enet::Http::getHeader() {
|
||||
}
|
||||
for (size_t iii=1; iii<list.size(); ++iii) {
|
||||
size_t found = list[iii].find(":");
|
||||
if (found == std::string::npos) {
|
||||
if (found == etk::String::npos) {
|
||||
// nothing
|
||||
continue;
|
||||
}
|
||||
std::string key = unEscapeChar(std::string(list[iii], 0, found));
|
||||
etk::String key = unEscapeChar(etk::String(list[iii], 0, found));
|
||||
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);
|
||||
ENET_VERBOSE("header : key='" << key << "' value='" << value << "'");
|
||||
if (m_isServer == false) {
|
||||
@@ -496,12 +545,13 @@ void enet::Http::getHeader() {
|
||||
m_connection.unlink();
|
||||
}
|
||||
}
|
||||
m_headerIsSend = true;
|
||||
if (m_isServer == false) {
|
||||
if (m_observerAnswer != nullptr) {
|
||||
if (m_observerAnswer != null) {
|
||||
m_observerAnswer(m_answerHeader);
|
||||
}
|
||||
} else {
|
||||
if (m_observerRequest != nullptr) {
|
||||
if (m_observerRequest != null) {
|
||||
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();
|
||||
std::string req = "GET http://" + m_connection.getName();
|
||||
etk::String req = "GET http://" + m_connection.getName();
|
||||
if (_address != "") {
|
||||
req += "/";
|
||||
req += _address;
|
||||
@@ -536,10 +586,10 @@ bool enet::Http::get(const std::string& _address) {
|
||||
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();
|
||||
// First create body :
|
||||
std::string body;
|
||||
etk::String body;
|
||||
for (auto &it : _values) {
|
||||
if (body.size() > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
std::string req = "POST http://" + m_connection.getName();
|
||||
etk::String req = "POST http://" + m_connection.getName();
|
||||
if (_address != "") {
|
||||
req += "/";
|
||||
req += _address;
|
||||
}
|
||||
req += " HTTP/1.0\n";
|
||||
setSendHeaderProperties("Content-Type", _contentType);
|
||||
setSendHeaderProperties("Content-Length", etk::to_string(_data.size()));
|
||||
setSendHeaderProperties("Content-Length", etk::toString(_data.size()));
|
||||
// add header properties :
|
||||
for (auto &it : m_header.m_map) {
|
||||
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);
|
||||
if (it == m_map.end()) {
|
||||
m_map.insert(make_pair(_key, _value));
|
||||
m_map.add(_key, _value);
|
||||
} else {
|
||||
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);
|
||||
if (it != m_map.end()) {
|
||||
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);
|
||||
if (it != m_map.end()) {
|
||||
return it->second;
|
||||
@@ -607,17 +657,64 @@ std::string enet::HttpHeader::getKey(const std::string& _key) const {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string enet::HttpHeader::generateKeys() const {
|
||||
std::string out;
|
||||
bool enet::HttpHeader::existKey(const etk::String& _key) const {
|
||||
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) {
|
||||
if ( it.first != ""
|
||||
&& it.second != "") {
|
||||
out += escapeChar(it.first) + " : " + escapeChar(it.second) + "\r\n";
|
||||
out += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
|
||||
}
|
||||
}
|
||||
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():
|
||||
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_helpMessage(_help) {
|
||||
|
||||
@@ -645,19 +742,26 @@ void enet::HttpAnswer::display() const {
|
||||
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 {
|
||||
std::string out;
|
||||
out += etk::to_string(m_protocol);
|
||||
etk::String enet::HttpAnswer::generate() const {
|
||||
etk::String out;
|
||||
out += etk::toString(m_protocol);
|
||||
out += " ";
|
||||
out += etk::to_string(int32_t(m_what));
|
||||
out += etk::toString(int32_t(m_what));
|
||||
out += " ";
|
||||
if (m_helpMessage != "") {
|
||||
out += escapeChar(m_helpMessage);
|
||||
} else {
|
||||
auto it = protocolName.find(m_what);
|
||||
if (it != protocolName.end()) {
|
||||
auto it = getProtocolName().find(m_what);
|
||||
if (it != getProtocolName().end()) {
|
||||
out += escapeChar(it->second);
|
||||
} else {
|
||||
out += "???";
|
||||
@@ -669,12 +773,12 @@ std::string enet::HttpAnswer::generate() const {
|
||||
return out;
|
||||
}
|
||||
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::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(" query:");
|
||||
for (auto &it : m_query) {
|
||||
if ( it.first != ""
|
||||
&& it.second != "") {
|
||||
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string enet::HttpRequest::generate() const {
|
||||
std::string out;
|
||||
out += etk::to_string(m_req);
|
||||
etk::String enet::HttpRequest::generate() const {
|
||||
etk::String out;
|
||||
out += etk::toString(m_req);
|
||||
out += " ";
|
||||
out += m_uri;
|
||||
etk::String querryData = generateQueryKeys();
|
||||
if (querryData.empty() != 0) {
|
||||
out += "?" + querryData;
|
||||
}
|
||||
out += " ";
|
||||
out += etk::to_string(m_protocol);
|
||||
out += etk::toString(m_protocol);
|
||||
out += "\r\n";
|
||||
out += generateKeys();
|
||||
out += "\r\n";
|
||||
@@ -713,17 +828,17 @@ std::string enet::HttpRequest::generate() const {
|
||||
}
|
||||
|
||||
|
||||
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPProtocol _obj) {
|
||||
_os << "enet::HTTPProtocol::" <<etk::to_string(_obj);
|
||||
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPProtocol _obj) {
|
||||
_os << "enet::HTTPProtocol::" <<etk::toString(_obj);
|
||||
return _os;
|
||||
}
|
||||
|
||||
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj) {
|
||||
_os << "enet::HTTPAnswerCode::" << etk::to_string(_obj);
|
||||
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPAnswerCode _obj) {
|
||||
_os << "enet::HTTPAnswerCode::" << etk::toString(_obj);
|
||||
return _os;
|
||||
}
|
||||
|
||||
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPReqType _obj) {
|
||||
_os << "enet::HTTPReqType::" << etk::to_string(_obj);
|
||||
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPReqType _obj) {
|
||||
_os << "enet::HTTPReqType::" << etk::toString(_obj);
|
||||
return _os;
|
||||
}
|
@@ -1,15 +1,16 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <enet/Tcp.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <ethread/tools.h>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <etk/Vector.hpp>
|
||||
#include <etk/Map.hpp>
|
||||
#include <ethread/Thread.hpp>
|
||||
#include <ethread/tools.hpp>
|
||||
#include <etk/Function.hpp>
|
||||
|
||||
namespace enet {
|
||||
enum class HTTPAnswerCode {
|
||||
@@ -63,7 +64,7 @@ namespace enet {
|
||||
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
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj);
|
||||
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPAnswerCode _obj);
|
||||
|
||||
enum class HTTPProtocol {
|
||||
http_0_1,
|
||||
@@ -110,18 +111,28 @@ namespace enet {
|
||||
http_3_9,
|
||||
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 {
|
||||
protected:
|
||||
// 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;
|
||||
public:
|
||||
void setKey(const std::string& _key, const std::string& _value);
|
||||
void rmKey(const std::string& _key);
|
||||
std::string getKey(const std::string& _key) const;
|
||||
void setKey(const etk::String& _key, const etk::String& _value);
|
||||
void rmKey(const etk::String& _key);
|
||||
etk::String getKey(const etk::String& _key) const;
|
||||
bool existKey(const etk::String& _key) const;
|
||||
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:
|
||||
enum HTTPProtocol getProtocol() const {
|
||||
return m_protocol;
|
||||
@@ -131,57 +142,58 @@ namespace enet {
|
||||
}
|
||||
HttpHeader();
|
||||
virtual ~HttpHeader() = default;
|
||||
virtual std::string generate() const = 0;
|
||||
virtual etk::String generate() const = 0;
|
||||
};
|
||||
|
||||
class HttpAnswer : public HttpHeader {
|
||||
private:
|
||||
enet::HTTPAnswerCode m_what;
|
||||
std::string m_helpMessage;
|
||||
etk::String m_helpMessage;
|
||||
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;
|
||||
std::string generate() const;
|
||||
etk::String generate() const;
|
||||
void setErrorCode(enum HTTPAnswerCode _value) {
|
||||
m_what = _value;
|
||||
}
|
||||
enum HTTPAnswerCode getErrorCode() const {
|
||||
return m_what;
|
||||
}
|
||||
void setHelp(const std::string& _value) {
|
||||
void setHelp(const etk::String& _value) {
|
||||
m_helpMessage = _value;
|
||||
}
|
||||
const std::string& getHelp() const {
|
||||
const etk::String& getHelp() const {
|
||||
return m_helpMessage;
|
||||
}
|
||||
};
|
||||
enum class HTTPReqType {
|
||||
GET,
|
||||
HEAD,
|
||||
POST,
|
||||
PUT,
|
||||
DELETE,
|
||||
HTTP_GET,
|
||||
HTTP_HEAD,
|
||||
HTTP_POST,
|
||||
HTTP_PUT,
|
||||
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 {
|
||||
private:
|
||||
// key, val
|
||||
enum HTTPReqType m_req;
|
||||
std::string m_uri;
|
||||
etk::String m_uri;
|
||||
public:
|
||||
HttpRequest(enum enet::HTTPReqType _type=enet::HTTPReqType::GET);
|
||||
HttpRequest(enum enet::HTTPReqType _type=enet::HTTPReqType::HTTP_GET);
|
||||
void display() const;
|
||||
std::string generate() const;
|
||||
etk::String generate() const;
|
||||
void setType(enum enet::HTTPReqType _value) {
|
||||
m_req = _value;
|
||||
}
|
||||
enum enet::HTTPReqType getType() const{
|
||||
return m_req;
|
||||
}
|
||||
void setUri(const std::string& _value) {
|
||||
void setUri(const etk::String& _value) {
|
||||
m_uri = _value;
|
||||
}
|
||||
const std::string& getUri() const {
|
||||
const etk::String& getUri() const {
|
||||
return m_uri;
|
||||
}
|
||||
};
|
||||
@@ -215,9 +227,17 @@ namespace enet {
|
||||
protected:
|
||||
enet::Tcp m_connection;
|
||||
bool m_headerIsSend;
|
||||
std::thread* m_thread;
|
||||
ethread::Thread* m_thread;
|
||||
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:
|
||||
void threadCallback();
|
||||
private:
|
||||
@@ -229,7 +249,14 @@ namespace enet {
|
||||
return m_connection.getConnectionStatus() == enet::Tcp::status::link;
|
||||
}
|
||||
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;
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
template<class CLASS_TYPE>
|
||||
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(std::vector<uint8_t>&)) {
|
||||
m_observer = [=](std::vector<uint8_t>& _value){
|
||||
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(etk::Vector<uint8_t>&)) {
|
||||
m_observer = [=](etk::Vector<uint8_t>& _value){
|
||||
(*_class.*_func)(_value);
|
||||
};
|
||||
}
|
||||
@@ -247,7 +274,7 @@ namespace enet {
|
||||
m_observer = _func;
|
||||
}
|
||||
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;
|
||||
/**
|
||||
* @brief Connect an function member on the signal with the shared_ptr object.
|
||||
@@ -265,11 +292,11 @@ namespace enet {
|
||||
m_observerRaw = _func;
|
||||
}
|
||||
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:
|
||||
ObserverRequest m_observerRequest;
|
||||
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:
|
||||
ObserverAnswer m_observerAnswer;
|
||||
public:
|
||||
@@ -288,7 +315,7 @@ namespace enet {
|
||||
* @return >0 byte size on the socket write
|
||||
* @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) {
|
||||
return 0;
|
||||
}
|
||||
@@ -305,7 +332,7 @@ namespace enet {
|
||||
* @return -1 an error occured.
|
||||
*/
|
||||
template <class T>
|
||||
int32_t write(const std::vector<T>& _data) {
|
||||
int32_t write(const etk::Vector<T>& _data) {
|
||||
if (_data.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -322,12 +349,13 @@ namespace enet {
|
||||
HttpClient(enet::Tcp _connection);
|
||||
public:
|
||||
void setHeader(const enet::HttpRequest& _header) {
|
||||
_header.display();
|
||||
setRequestHeader(_header);
|
||||
}
|
||||
public:
|
||||
//bool get(const std::string& _address);
|
||||
//bool post(const std::string& _address, const std::map<std::string, std::string>& _values);
|
||||
//bool post(const std::string& _address, const std::string& _contentType, const std::string& _data);
|
||||
//bool get(const etk::String& _address);
|
||||
//bool post(const etk::String& _address, const etk::Map<etk::String, etk::String>& _values);
|
||||
//bool post(const etk::String& _address, const etk::String& _contentType, const etk::String& _data);
|
||||
public:
|
||||
/**
|
||||
* @brief Connect an function member on the signal with the shared_ptr object.
|
||||
@@ -351,6 +379,7 @@ namespace enet {
|
||||
HttpServer(enet::Tcp _connection);
|
||||
public:
|
||||
void setHeader(const enet::HttpAnswer& _header) {
|
||||
_header.display();
|
||||
setAnswerHeader(_header);
|
||||
}
|
||||
public:
|
154
enet/Tcp.cpp
154
enet/Tcp.cpp
@@ -1,20 +1,33 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <netinet/tcp.h>
|
||||
extern "C" {
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
}
|
||||
#include <etk/stdTools.hpp>
|
||||
#include <ethread/tools.hpp>
|
||||
|
||||
#ifdef __TARGET_OS__Windows
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENET_STORE_INPUT
|
||||
static uint32_t baseID = 0;
|
||||
#endif
|
||||
|
||||
bool enet::Tcp::setTCPNoDelay(bool _enabled) {
|
||||
if (m_socketId >= 0) {
|
||||
@@ -29,65 +42,92 @@ bool enet::Tcp::setTCPNoDelay(bool _enabled) {
|
||||
|
||||
|
||||
enet::Tcp::Tcp() :
|
||||
#ifdef __TARGET_OS__Windows
|
||||
m_socketId(INVALID_SOCKET),
|
||||
#else
|
||||
m_socketId(-1),
|
||||
#endif
|
||||
m_name(),
|
||||
m_status(status::error) {
|
||||
|
||||
}
|
||||
|
||||
enet::Tcp::Tcp(int32_t _idSocket, const std::string& _name) :
|
||||
#ifdef __TARGET_OS__Windows
|
||||
enet::Tcp::Tcp(SOCKET _idSocket, const etk::String& _name, const etk::String& _remoteName) :
|
||||
#else
|
||||
enet::Tcp::Tcp(int32_t _idSocket, const etk::String& _name, const etk::String& _remoteName) :
|
||||
#endif
|
||||
m_socketId(_idSocket),
|
||||
m_name(_name),
|
||||
m_remoteName(_remoteName),
|
||||
m_status(status::link) {
|
||||
#if 1
|
||||
//Initialize the pollfd structure
|
||||
memset(m_fds, 0 , sizeof(m_fds));
|
||||
//Set up the initial listening socket
|
||||
m_fds[0].fd = _idSocket;
|
||||
m_fds[0].events = POLLIN | POLLERR;
|
||||
#ifdef ENET_STORE_INPUT
|
||||
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
|
||||
m_nodeStoreInput.fileOpenWrite();
|
||||
#endif
|
||||
}
|
||||
|
||||
enet::Tcp::Tcp(Tcp&& _obj) :
|
||||
m_socketId(_obj.m_socketId),
|
||||
m_name(_obj.m_name),
|
||||
m_remoteName(_obj.m_remoteName),
|
||||
m_status(_obj.m_status) {
|
||||
_obj.m_socketId = -1;
|
||||
#ifdef ENET_STORE_INPUT
|
||||
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
|
||||
m_nodeStoreInput.fileOpenWrite();
|
||||
#endif
|
||||
#ifdef __TARGET_OS__Windows
|
||||
_obj.m_socketId = INVALID_SOCKET;
|
||||
#else
|
||||
_obj.m_socketId = -1;
|
||||
#endif
|
||||
_obj.m_name = "";
|
||||
_obj.m_status = status::error;
|
||||
m_fds[0] = _obj.m_fds[0];
|
||||
#if 1
|
||||
memset(_obj.m_fds, 0 , sizeof(_obj.m_fds));
|
||||
#endif
|
||||
}
|
||||
|
||||
enet::Tcp::~Tcp() {
|
||||
unlink();
|
||||
}
|
||||
|
||||
enet::Tcp& enet::Tcp::operator = (enet::Tcp&& _obj) {
|
||||
unlink();
|
||||
#ifdef ENET_STORE_INPUT
|
||||
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
|
||||
m_nodeStoreInput.fileOpenWrite();
|
||||
#endif
|
||||
m_socketId = _obj.m_socketId;
|
||||
_obj.m_socketId = -1;
|
||||
#ifdef __TARGET_OS__Windows
|
||||
_obj.m_socketId = INVALID_SOCKET;
|
||||
#else
|
||||
_obj.m_socketId = -1;
|
||||
#endif
|
||||
m_name = _obj.m_name;
|
||||
_obj.m_name = "";
|
||||
m_status = _obj.m_status;
|
||||
_obj.m_status = status::error;
|
||||
m_fds[0] = _obj.m_fds[0];
|
||||
#if 1
|
||||
memset(_obj.m_fds, 0 , sizeof(_obj.m_fds));
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool enet::Tcp::unlink() {
|
||||
// prevent call while stoping ...
|
||||
m_status = status::unlink;
|
||||
if (m_socketId >= 0) {
|
||||
ENET_INFO("Close socket (start)");
|
||||
shutdown(m_socketId, SHUT_RDWR);
|
||||
close(m_socketId);
|
||||
#ifdef __TARGET_OS__Windows
|
||||
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);
|
||||
m_socketId = INVALID_SOCKET;
|
||||
#else
|
||||
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);
|
||||
m_socketId = -1;
|
||||
#endif
|
||||
ENET_INFO("Close socket (done)");
|
||||
m_socketId = -1;
|
||||
}
|
||||
m_status = status::unlink;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -98,29 +138,38 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
||||
return -1;
|
||||
}
|
||||
int32_t size = -1;
|
||||
int nfds = 1;
|
||||
|
||||
fd_set sock;
|
||||
// Initialize the timeout to 3 minutes. If no activity after 3 minutes this program will end. timeout value is based on milliseconds.
|
||||
int timeout = (3 * 60 * 1000);
|
||||
// Call poll() and wait 3 minutes for it to complete.
|
||||
int rc = poll(m_fds, nfds, timeout);
|
||||
struct timeval timeOutStruct;
|
||||
timeOutStruct.tv_sec = (3 * 60 * 1000);
|
||||
timeOutStruct.tv_usec = 0;
|
||||
FD_ZERO(&sock);
|
||||
FD_SET(m_socketId,&sock);
|
||||
ENET_VERBOSE(" select ...");
|
||||
int rc = select(m_socketId+1, &sock, NULL, NULL, &timeOutStruct);
|
||||
ENET_VERBOSE(" select (done)");
|
||||
// Check to see if the poll call failed.
|
||||
if (rc < 0) {
|
||||
ENET_ERROR(" poll() failed");
|
||||
return-1;
|
||||
ENET_ERROR(" select() failed");
|
||||
return -1;
|
||||
}
|
||||
// Check to see if the 3 minute time out expired.
|
||||
if (rc == 0) {
|
||||
ENET_ERROR(" poll() timed out.\n");
|
||||
ENET_ERROR(" select() timed out.");
|
||||
return -2;
|
||||
}
|
||||
if (!FD_ISSET(m_socketId, &sock)) {
|
||||
ENET_ERROR(" select() id is not set...");
|
||||
return -1;
|
||||
}
|
||||
bool closeConn = false;
|
||||
// Receive all incoming data on this socket before we loop back and call poll again.
|
||||
// Receive data on this connection until the recv fails with EWOULDBLOCK.
|
||||
// If any other failure occurs, we will close the connection.
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
//ENET_DEBUG("Read on socketid = " << m_fds[0].fd );
|
||||
rc = recv(m_fds[0].fd, _data, _maxLen, 0);
|
||||
ethread::UniqueLock lock(m_mutex);
|
||||
rc = recv(m_socketId, (char *)_data, _maxLen, 0);
|
||||
}
|
||||
if (rc < 0) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
@@ -132,6 +181,7 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
||||
if (rc == 0) {
|
||||
ENET_INFO("Connection closed");
|
||||
closeConn = true;
|
||||
size = 0;
|
||||
}
|
||||
if (closeConn == false) {
|
||||
// Data was received
|
||||
@@ -142,6 +192,9 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
|
||||
ENET_DEBUG(" Set status at remote close ...");
|
||||
m_status = status::linkRemoteClose;
|
||||
}
|
||||
#ifdef ENET_STORE_INPUT
|
||||
m_nodeStoreInput.fileWrite(_data, 1, size);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -151,11 +204,24 @@ int32_t enet::Tcp::write(const void* _data, int32_t _len) {
|
||||
ENET_ERROR("Can not write on unlink connection");
|
||||
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 );
|
||||
int32_t size;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
size = ::write(m_socketId, _data, _len);
|
||||
ethread::UniqueLock lock(m_mutex);
|
||||
size = ::send(m_socketId, (const char *)_data, _len, 0);
|
||||
}
|
||||
if ( size != _len
|
||||
&& errno != 0) {
|
||||
|
@@ -1,23 +1,43 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <poll.h>
|
||||
#include <mutex>
|
||||
#include <etk/types.hpp>
|
||||
#include <ethread/Mutex.hpp>
|
||||
#include <etk/Function.hpp>
|
||||
#ifdef __TARGET_OS__Windows
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
//#define ENET_STORE_INPUT
|
||||
|
||||
#ifdef ENET_STORE_INPUT
|
||||
#include <etk/os/FSNode.hpp>
|
||||
#endif
|
||||
|
||||
namespace enet {
|
||||
class Tcp {
|
||||
private:
|
||||
int32_t m_socketId; //!< socket linux interface generic
|
||||
struct pollfd m_fds[1];
|
||||
std::mutex m_mutex;
|
||||
#ifdef __TARGET_OS__Windows
|
||||
SOCKET m_socketId; //!< socket Windows interface generic
|
||||
#else
|
||||
int32_t m_socketId; //!< socket linux interface generic
|
||||
#endif
|
||||
#ifdef ENET_STORE_INPUT
|
||||
etk::FSNode m_nodeStoreInput;
|
||||
#endif
|
||||
ethread::Mutex m_mutex;
|
||||
public:
|
||||
Tcp();
|
||||
Tcp(int32_t _idSocket, const std::string& _name);
|
||||
#ifdef __TARGET_OS__Windows
|
||||
Tcp(SOCKET _idSocket, const etk::String& _name, const etk::String& _remoteName="");
|
||||
#else
|
||||
Tcp(int32_t _idSocket, const etk::String& _name, const etk::String& _remoteName="");
|
||||
#endif
|
||||
// move constructor
|
||||
Tcp(Tcp&& _obj);
|
||||
// Move operator;
|
||||
@@ -26,15 +46,25 @@ namespace enet {
|
||||
Tcp& operator= (Tcp& _obj) = delete;
|
||||
virtual ~Tcp();
|
||||
private:
|
||||
std::string m_name; //!< hostname/IP:port.
|
||||
etk::String m_name; //!< hostname/IP:port.
|
||||
public:
|
||||
/**
|
||||
* @brief Get the decriptive name hot the host:port
|
||||
* @return the string requested
|
||||
*/
|
||||
const std::string& getName() {
|
||||
const etk::String& getName() const {
|
||||
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:
|
||||
enum class status {
|
||||
unlink,
|
||||
@@ -82,7 +112,7 @@ namespace enet {
|
||||
* @return >0 byte size on the socket write
|
||||
* @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) {
|
||||
return 0;
|
||||
}
|
||||
@@ -99,7 +129,7 @@ namespace enet {
|
||||
* @return -1 an error occured.
|
||||
*/
|
||||
template <class T>
|
||||
int32_t write(const std::vector<T>& _data) {
|
||||
int32_t write(const etk::Vector<T>& _data) {
|
||||
if (_data.size() == 0) {
|
||||
return 0;
|
||||
}
|
@@ -1,79 +1,206 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/TcpClient.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry) {
|
||||
std::string tmpname;
|
||||
tmpname = etk::to_string(_ip1);
|
||||
tmpname += ".";
|
||||
tmpname += etk::to_string(_ip2);
|
||||
tmpname += ".";
|
||||
tmpname += etk::to_string(_ip3);
|
||||
tmpname += ".";
|
||||
tmpname += etk::to_string(_ip4);
|
||||
return std::move(enet::connectTcpClient(tmpname, _port, _numberRetry));
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/TcpClient.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
}
|
||||
enet::Tcp enet::connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry) {
|
||||
int32_t socketId = -1;
|
||||
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
||||
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
||||
// open in Socket normal mode
|
||||
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socketId < 0) {
|
||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||
usleep(200000);
|
||||
continue;
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
#ifdef __TARGET_OS__Windows
|
||||
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
enet::Tcp enet::connectTcpClient(const etk::String& _config, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||
size_t pos = _config.find(':');
|
||||
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 += etk::toString(_ip2);
|
||||
tmpname += ".";
|
||||
tmpname += etk::toString(_ip3);
|
||||
tmpname += ".";
|
||||
tmpname += etk::toString(_ip4);
|
||||
return etk::move(enet::connectTcpClient(tmpname, _port, _numberRetry, _timeOut));
|
||||
}
|
||||
|
||||
#ifdef __TARGET_OS__Windows
|
||||
enet::Tcp enet::connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||
if (enet::isInit() == false) {
|
||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
||||
struct sockaddr_in servAddr;
|
||||
struct hostent* server = gethostbyname(_hostname.c_str());
|
||||
if (server == nullptr) {
|
||||
ENET_ERROR("ERROR, no such host : " << _hostname);
|
||||
usleep(200000);
|
||||
continue;
|
||||
if (_hostname == "") {
|
||||
ENET_ERROR("get connection wihtout hostname");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
bzero((char *) &servAddr, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
bcopy((char *)server->h_addr, (char *)&servAddr.sin_addr.s_addr, server->h_length);
|
||||
servAddr.sin_port = htons(_port);
|
||||
ENET_INFO("Start connexion ...");
|
||||
if (connect(socketId, (struct sockaddr *)&servAddr,sizeof(servAddr)) != 0) {
|
||||
if(errno != EINPROGRESS) {
|
||||
if( errno != ENOENT
|
||||
&& errno != EAGAIN
|
||||
&& errno != ECONNREFUSED) {
|
||||
ENET_ERROR("ERROR connecting on : errno=" << errno << "," << strerror(errno));
|
||||
}
|
||||
close(socketId);
|
||||
socketId = -1;
|
||||
SOCKET socketId = INVALID_SOCKET;
|
||||
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
||||
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
||||
if (iii > 0) {
|
||||
ethread::sleepMilliSeconds((200));
|
||||
}
|
||||
// open in Socket normal mode
|
||||
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socketId < 0) {
|
||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||
continue;
|
||||
}
|
||||
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
||||
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
// Resolve the server address and port
|
||||
struct addrinfo* result = null;
|
||||
etk::String portValue = etk::toString(_port);
|
||||
int iResult = getaddrinfo(_hostname.c_str(), portValue.c_str(), &hints, &result);
|
||||
if (iResult != 0) {
|
||||
ENET_ERROR("getaddrinfo failed with error: " << iResult);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attempt to connect to an address until one succeeds
|
||||
for(struct addrinfo* ptr=result;
|
||||
ptr != null;
|
||||
ptr=ptr->ai_next) {
|
||||
ENET_DEBUG(" find one ...");
|
||||
// Create a SOCKET for connecting to server
|
||||
socketId = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
|
||||
if (socketId == INVALID_SOCKET) {
|
||||
ENET_ERROR("socket failed with error: " << WSAGetLastError());
|
||||
break;
|
||||
}
|
||||
// Connect to server.
|
||||
iResult = connect(socketId, ptr->ai_addr, (int)ptr->ai_addrlen);
|
||||
if (iResult == SOCKET_ERROR) {
|
||||
ENET_ERROR("socket connection failed with error: " << WSAGetLastError());
|
||||
closesocket(socketId);
|
||||
socketId = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
|
||||
if (socketId == INVALID_SOCKET) {
|
||||
ENET_ERROR("Unable to connect to server!");
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
ENET_ERROR("ERROR connecting, maybe retry ... errno=" << errno << "," << strerror(errno));
|
||||
usleep(500000);
|
||||
continue;
|
||||
}
|
||||
// if we are here ==> then the connextion is done corectly ...
|
||||
break;
|
||||
if (socketId == INVALID_SOCKET) {
|
||||
ENET_ERROR("ERROR connecting ... (after all try)");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
ENET_DEBUG("Connection done");
|
||||
return etk::move(enet::Tcp(socketId, _hostname + ":" + etk::toString(_port)));
|
||||
}
|
||||
if (socketId<0) {
|
||||
ENET_ERROR("ERROR connecting ... (after all try)");
|
||||
return std::move(enet::Tcp());
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
enet::Tcp enet::connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
|
||||
if (enet::isInit() == false) {
|
||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
if (_hostname == "") {
|
||||
ENET_ERROR("get connection wihtout hostname");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
int32_t socketId = -1;
|
||||
ENET_INFO("Start connection on " << _hostname << ":" << _port);
|
||||
for(int32_t iii=0; iii<_numberRetry ;iii++) {
|
||||
if (iii > 0) {
|
||||
ethread::sleepMilliSeconds((200));
|
||||
}
|
||||
// open in Socket normal mode
|
||||
socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socketId < 0) {
|
||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||
continue;
|
||||
}
|
||||
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
|
||||
struct sockaddr_in servAddr;
|
||||
struct hostent* server = null;
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
bzero((char *) &servAddr, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
bcopy((char *)server->h_addr, (char *)&servAddr.sin_addr.s_addr, server->h_length);
|
||||
servAddr.sin_port = htons(_port);
|
||||
ENET_INFO("Start connexion ...");
|
||||
if (connect(socketId, (struct sockaddr *)&servAddr, sizeof(servAddr)) != 0) {
|
||||
if(errno != EINPROGRESS) {
|
||||
if( errno != ENOENT
|
||||
&& errno != EAGAIN
|
||||
&& errno != ECONNREFUSED) {
|
||||
ENET_ERROR("ERROR connecting on : errno=" << errno << "," << strerror(errno));
|
||||
}
|
||||
#ifdef __TARGET_OS__Windows
|
||||
closesocket(socketId);
|
||||
#else
|
||||
close(socketId);
|
||||
#endif
|
||||
socketId = -1;
|
||||
}
|
||||
ENET_ERROR("ERROR connecting, maybe retry ... errno=" << errno << "," << strerror(errno));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (socketId<0) {
|
||||
ENET_ERROR("ERROR connecting ... (after all try)");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
ENET_INFO("Connection done");
|
||||
return etk::move(enet::Tcp(socketId, _hostname + ":" + etk::toString(_port)));
|
||||
}
|
||||
ENET_DEBUG("Connection done");
|
||||
return std::move(enet::Tcp(socketId, _hostname + ":" + etk::to_string(_port)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -1,13 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <enet/Tcp.h>
|
||||
|
||||
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(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry=5);
|
||||
}
|
15
enet/TcpClient.hpp
Normal file
15
enet/TcpClient.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <echrono/Duration.hpp>
|
||||
|
||||
namespace enet {
|
||||
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 etk::String& _hostname, uint16_t _port, uint32_t _numberRetry=5, echrono::Duration _timeOut = echrono::seconds(1));
|
||||
enet::Tcp connectTcpClient(const etk::String& _config, uint32_t _numberRetry, echrono::Duration _timeOut);
|
||||
}
|
@@ -1,21 +1,31 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/TcpServer.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/TcpServer.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
}
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
#ifdef __TARGET_OS__Windows
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
//https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms737889(v=vs.85).aspx
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
enet::TcpServer::TcpServer() :
|
||||
m_socketId(-1),
|
||||
@@ -29,18 +39,18 @@ enet::TcpServer::~TcpServer() {
|
||||
}
|
||||
|
||||
void enet::TcpServer::setIpV4(uint8_t _fist, uint8_t _second, uint8_t _third, uint8_t _quatro) {
|
||||
std::string tmpname;
|
||||
tmpname = etk::to_string(_fist);
|
||||
etk::String tmpname;
|
||||
tmpname = etk::toString(_fist);
|
||||
tmpname += ".";
|
||||
tmpname += etk::to_string(_second);
|
||||
tmpname += etk::toString(_second);
|
||||
tmpname += ".";
|
||||
tmpname += etk::to_string(_third);
|
||||
tmpname += etk::toString(_third);
|
||||
tmpname += ".";
|
||||
tmpname += etk::to_string(_quatro);
|
||||
tmpname += etk::toString(_quatro);
|
||||
setHostNane(tmpname);
|
||||
}
|
||||
|
||||
void enet::TcpServer::setHostNane(const std::string& _name) {
|
||||
void enet::TcpServer::setHostNane(const etk::String& _name) {
|
||||
if (_name == m_host) {
|
||||
return;
|
||||
}
|
||||
@@ -54,59 +64,192 @@ void enet::TcpServer::setPort(uint16_t _port) {
|
||||
m_port = _port;
|
||||
}
|
||||
|
||||
bool enet::TcpServer::link() {
|
||||
ENET_INFO("Start connection on " << m_host << ":" << m_port);
|
||||
// open in Socket normal mode
|
||||
m_socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (m_socketId < 0) {
|
||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||
return false;
|
||||
#ifdef __TARGET_OS__Windows
|
||||
bool enet::TcpServer::link() {
|
||||
if (enet::isInit() == false) {
|
||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||
return false;
|
||||
}
|
||||
ENET_INFO("Start connection on " << m_host << ":" << m_port);
|
||||
|
||||
struct addrinfo *result = null;
|
||||
struct addrinfo hints;
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
// Resolve the server address and port
|
||||
etk::String portValue = etk::toString(m_port);
|
||||
int iResult = getaddrinfo(null, portValue.c_str(), &hints, &result);
|
||||
if (iResult != 0) {
|
||||
ENET_ERROR("getaddrinfo failed with error: " << iResult);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// open in Socket normal mode
|
||||
m_socketId = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||
if (m_socketId == INVALID_SOCKET) {
|
||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||
freeaddrinfo(result);
|
||||
return false;
|
||||
}
|
||||
// set the reuse of the socket if previously opened :
|
||||
int sockOpt = 1;
|
||||
if(setsockopt(m_socketId, SOL_SOCKET, SO_REUSEADDR, (const char*)&sockOpt, sizeof(int)) != 0) {
|
||||
ENET_ERROR("ERROR while configuring socket re-use : errno=" << errno << "," << strerror(errno));
|
||||
return false;
|
||||
}
|
||||
ENET_INFO("Start binding Socket ... (can take some time ...)");
|
||||
if (bind(m_socketId, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR) {
|
||||
ENET_ERROR("ERROR on binding errno=" << WSAGetLastError());
|
||||
freeaddrinfo(result);
|
||||
closesocket(m_socketId);
|
||||
m_socketId = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// set the reuse of the socket if previously opened :
|
||||
int sockOpt = 1;
|
||||
if(setsockopt(m_socketId, SOL_SOCKET, SO_REUSEADDR, (const char*)&sockOpt, sizeof(int)) != 0) {
|
||||
ENET_ERROR("ERROR while configuring socket re-use : errno=" << errno << "," << strerror(errno));
|
||||
return false;
|
||||
#else
|
||||
bool enet::TcpServer::link() {
|
||||
if (enet::isInit() == false) {
|
||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||
return false;
|
||||
}
|
||||
ENET_INFO("Start connection on " << m_host << ":" << m_port);
|
||||
// open in Socket normal mode
|
||||
m_socketId = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (m_socketId < 0) {
|
||||
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
|
||||
return false;
|
||||
}
|
||||
// set the reuse of the socket if previously opened :
|
||||
int sockOpt = 1;
|
||||
if(setsockopt(m_socketId, SOL_SOCKET, SO_REUSEADDR, (const char*)&sockOpt, sizeof(int)) != 0) {
|
||||
ENET_ERROR("ERROR while configuring socket re-use : errno=" << errno << "," << strerror(errno));
|
||||
return false;
|
||||
}
|
||||
// clear all
|
||||
struct sockaddr_in servAddr;
|
||||
bzero((char *) &servAddr, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
servAddr.sin_port = htons(m_port);
|
||||
ENET_INFO("Start binding Socket ... (can take some time ...)");
|
||||
if (bind(m_socketId, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) {
|
||||
ENET_ERROR("ERROR on binding errno=" << errno << "," << strerror(errno));
|
||||
#ifdef __TARGET_OS__Windows
|
||||
closesocket(m_socketId);
|
||||
m_socketId = INVALID_SOCKET;
|
||||
#else
|
||||
close(m_socketId);
|
||||
m_socketId = -1;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// clear all
|
||||
struct sockaddr_in servAddr;
|
||||
bzero((char *) &servAddr, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
servAddr.sin_port = htons(m_port);
|
||||
ENET_INFO("Start binding Socket ... (can take some time ...)");
|
||||
if (bind(m_socketId, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) {
|
||||
ENET_ERROR("ERROR on binding errno=" << errno << "," << strerror(errno));
|
||||
close(m_socketId);
|
||||
m_socketId = -1;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
enet::Tcp enet::TcpServer::waitNext() {
|
||||
if (enet::isInit() == false) {
|
||||
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
|
||||
return etk::move(enet::Tcp());
|
||||
}
|
||||
ENET_INFO("End binding Socket ... (start listen)");
|
||||
listen(m_socketId,1); // 1 is for the number of connection at the same time ...
|
||||
#ifdef __TARGET_OS__Windows
|
||||
int ret = listen(m_socketId, SOMAXCONN);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
ENET_ERROR("listen failed with error: " << WSAGetLastError());
|
||||
return enet::Tcp();;
|
||||
}
|
||||
#else
|
||||
listen(m_socketId, 1); // 1 is for the number of connection at the same time ...
|
||||
#endif
|
||||
ENET_INFO("End listen Socket ... (start accept)");
|
||||
struct sockaddr_in clientAddr;
|
||||
socklen_t clilen = sizeof(clientAddr);
|
||||
int32_t socketIdClient = accept(m_socketId, (struct sockaddr *) &clientAddr, &clilen);
|
||||
if (socketIdClient < 0) {
|
||||
ENET_ERROR("ERROR on accept errno=" << errno << "," << strerror(errno));
|
||||
close(m_socketId);
|
||||
m_socketId = -1;
|
||||
#ifdef __TARGET_OS__Windows
|
||||
closesocket(m_socketId);
|
||||
m_socketId = INVALID_SOCKET;
|
||||
#else
|
||||
close(m_socketId);
|
||||
m_socketId = -1;
|
||||
#endif
|
||||
|
||||
return enet::Tcp();
|
||||
}
|
||||
ENET_INFO("End configuring Socket ... Find New one");
|
||||
return enet::Tcp(socketIdClient, m_host + ":" + etk::to_string(m_port));
|
||||
etk::String remoteAddress;
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
bool enet::TcpServer::unlink() {
|
||||
if (m_socketId >= 0) {
|
||||
ENET_INFO(" close server socket");
|
||||
close(m_socketId);
|
||||
m_socketId = -1;
|
||||
}
|
||||
#ifdef __TARGET_OS__Windows
|
||||
if (m_socketId != INVALID_SOCKET) {
|
||||
ENET_INFO(" close server socket");
|
||||
closesocket(m_socketId);
|
||||
m_socketId = INVALID_SOCKET;
|
||||
}
|
||||
#else
|
||||
if (m_socketId >= 0) {
|
||||
ENET_INFO(" close server socket");
|
||||
close(m_socketId);
|
||||
m_socketId = -1;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@@ -1,25 +1,32 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <poll.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/Tcp.hpp>
|
||||
#ifdef __TARGET_OS__Windows
|
||||
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
namespace enet {
|
||||
class TcpServer {
|
||||
private:
|
||||
int32_t m_socketId; //!< socket linux interface generic
|
||||
#if 1
|
||||
#ifdef __TARGET_OS__Windows
|
||||
SOCKET m_socketId; //!< socket Windows interface generic
|
||||
#else
|
||||
int32_t m_socketId; //!< socket linux interface generic
|
||||
#endif
|
||||
#ifndef __TARGET_OS__Windows
|
||||
struct pollfd m_fds[1];
|
||||
#endif
|
||||
public:
|
||||
TcpServer();
|
||||
virtual ~TcpServer();
|
||||
private:
|
||||
std::string m_host; //!< hostname/IP to connect with.
|
||||
etk::String m_host; //!< hostname/IP to connect with.
|
||||
public:
|
||||
/**
|
||||
* @brief Set the connection IP id.
|
||||
@@ -33,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".
|
||||
* @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
|
||||
* @return the string requested
|
||||
*/
|
||||
const std::string& getHostName() {
|
||||
const etk::String& getHostName() {
|
||||
return m_host;
|
||||
}
|
||||
private:
|
@@ -1,9 +1,9 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/Udp.h>
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/Udp.hpp>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
@@ -1,18 +1,18 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/WebSocket.h>
|
||||
#include <map>
|
||||
#include <etk/stdTools.h>
|
||||
#include <string.h>
|
||||
#include <random>
|
||||
#include <algue/base64.h>
|
||||
#include <algue/sha1.h>
|
||||
#include <unistd.h>
|
||||
#include <enet/debug.hpp>
|
||||
#include <enet/WebSocket.hpp>
|
||||
#include <etk/Map.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
#include <etk/String.hpp>
|
||||
#include <etk/tool.hpp>
|
||||
#include <algue/base64.hpp>
|
||||
#include <algue/sha1.hpp>
|
||||
|
||||
|
||||
|
||||
namespace enet {
|
||||
@@ -29,54 +29,44 @@ namespace enet {
|
||||
|
||||
enet::WebSocket::WebSocket() :
|
||||
m_connectionValidate(false),
|
||||
m_interface(nullptr),
|
||||
m_observer(nullptr),
|
||||
m_observerUriCheck(nullptr) {
|
||||
m_interface(null),
|
||||
m_observer(null),
|
||||
m_observerUriCheck(null) {
|
||||
|
||||
}
|
||||
|
||||
enet::WebSocket::WebSocket(enet::Tcp _connection, bool _isServer) :
|
||||
m_connectionValidate(false),
|
||||
m_interface(nullptr),
|
||||
m_observer(nullptr),
|
||||
m_observerUriCheck(nullptr) {
|
||||
_connection.setTCPNoDelay(true);
|
||||
if (_isServer == true) {
|
||||
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(std::move(_connection));
|
||||
m_interface = interface;
|
||||
if (interface != nullptr) {
|
||||
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
m_interface(null),
|
||||
m_observer(null),
|
||||
m_observerUriCheck(null) {
|
||||
setInterface(etk::move(_connection), _isServer);
|
||||
}
|
||||
|
||||
const etk::String& enet::WebSocket::getRemoteAddress() const {
|
||||
if (m_interface == null) {
|
||||
static const etk::String tmpOut;
|
||||
return tmpOut;
|
||||
}
|
||||
if (m_interface == nullptr) {
|
||||
ENET_ERROR("can not create interface for the websocket");
|
||||
return;
|
||||
}
|
||||
m_interface->connectRaw(this, &enet::WebSocket::onReceiveData);
|
||||
return m_interface->getRemoteAddress();
|
||||
}
|
||||
|
||||
void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
|
||||
_connection.setTCPNoDelay(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;
|
||||
if (interface != nullptr) {
|
||||
if (interface != null) {
|
||||
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
|
||||
}
|
||||
} 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;
|
||||
if (interface != nullptr) {
|
||||
if (interface != null) {
|
||||
interface->connectHeader(this, &enet::WebSocket::onReceiveAnswer);
|
||||
}
|
||||
}
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("can not create interface for the websocket");
|
||||
return;
|
||||
}
|
||||
@@ -84,84 +74,93 @@ void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
|
||||
}
|
||||
|
||||
enet::WebSocket::~WebSocket() {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
return;
|
||||
}
|
||||
stop(true);
|
||||
}
|
||||
|
||||
static std::string generateKey() {
|
||||
// create dynamic key:
|
||||
std::random_device rd;
|
||||
std::mt19937 e2(rd());
|
||||
std::uniform_real_distribution<> dist(0, 0xFF);
|
||||
static etk::String generateKey() {
|
||||
uint8_t dataKey[16];
|
||||
// create dynamic key:
|
||||
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);
|
||||
}
|
||||
|
||||
static std::string generateCheckKey(const std::string& _key) {
|
||||
std::string out = _key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
std::vector<uint8_t> keyData = algue::sha1::encode(out);
|
||||
static etk::String generateCheckKey(const etk::String& _key) {
|
||||
etk::String out = _key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
etk::Vector<uint8_t> keyData = algue::sha1::encode(out);
|
||||
return algue::base64::encode(keyData);
|
||||
}
|
||||
|
||||
void enet::WebSocket::start(const std::string& _uri, const std::vector<std::string>& _listProtocols) {
|
||||
if (m_interface == nullptr) {
|
||||
void enet::WebSocket::start(const etk::String& _uri, const etk::Vector<etk::String>& _listProtocols) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
m_interface->start();
|
||||
if (m_interface->isServer() == false) {
|
||||
enet::HttpRequest req(enet::HTTPReqType::GET);
|
||||
req.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||
req.setUri(_uri);
|
||||
req.setKey("Upgrade", "websocket");
|
||||
req.setKey("Connection", "Upgrade");
|
||||
m_checkKey = generateKey();
|
||||
req.setKey("Sec-WebSocket-Key", m_checkKey); // this is an example key ...
|
||||
m_checkKey = generateCheckKey(m_checkKey);
|
||||
req.setKey("Sec-WebSocket-Version", "13");
|
||||
req.setKey("Pragma", "no-cache");
|
||||
req.setKey("Cache-Control", "no-cache");
|
||||
std::string protocolList;
|
||||
for (auto &it : _listProtocols) {
|
||||
if (it == "") {
|
||||
continue;
|
||||
if (m_interface->isServer() == true) {
|
||||
m_interface->start();
|
||||
} else {
|
||||
do {
|
||||
m_redirectInProgress = false;
|
||||
m_interface->start();
|
||||
enet::HttpRequest req(enet::HTTPReqType::HTTP_GET);
|
||||
req.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||
req.setUri(_uri);
|
||||
req.setKey("Upgrade", "websocket");
|
||||
req.setKey("Connection", "Upgrade");
|
||||
m_checkKey = generateKey();
|
||||
req.setKey("Sec-WebSocket-Key", m_checkKey); // this is an example key ...
|
||||
m_checkKey = generateCheckKey(m_checkKey);
|
||||
req.setKey("Sec-WebSocket-Version", "13");
|
||||
req.setKey("Pragma", "no-cache");
|
||||
req.setKey("Cache-Control", "no-cache");
|
||||
etk::String protocolList;
|
||||
for (auto &it : _listProtocols) {
|
||||
if (it == "") {
|
||||
continue;
|
||||
}
|
||||
if (protocolList != "") {
|
||||
protocolList += ", ";
|
||||
}
|
||||
protocolList += it;
|
||||
}
|
||||
if (protocolList != "") {
|
||||
protocolList += ", ";
|
||||
req.setKey("Sec-WebSocket-Protocol", protocolList);
|
||||
}
|
||||
protocolList += it;
|
||||
}
|
||||
if (protocolList != "") {
|
||||
req.setKey("Sec-WebSocket-Protocol", protocolList);
|
||||
}
|
||||
ememory::SharedPtr<enet::HttpClient> interface = ememory::dynamicPointerCast<enet::HttpClient>(m_interface);
|
||||
if (interface != nullptr) {
|
||||
interface->setHeader(req);
|
||||
int32_t timeout = 500000; // 5 second
|
||||
while (timeout>=0) {
|
||||
if ( m_connectionValidate == true
|
||||
|| m_interface->isAlive() == false) {
|
||||
break;
|
||||
ememory::SharedPtr<enet::HttpClient> interface = ememory::dynamicPointerCast<enet::HttpClient>(m_interface);
|
||||
if (interface != null) {
|
||||
interface->setHeader(req);
|
||||
int32_t timeout = 500000; // 5 second
|
||||
while ( timeout>=0
|
||||
&& m_redirectInProgress == false) {
|
||||
if ( m_connectionValidate == true
|
||||
|| m_interface->isAlive() == false) {
|
||||
break;
|
||||
}
|
||||
ethread::sleepMilliSeconds(10);
|
||||
timeout--;
|
||||
}
|
||||
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 ...");
|
||||
}
|
||||
}
|
||||
usleep(10000);
|
||||
timeout--;
|
||||
}
|
||||
if ( m_connectionValidate == false
|
||||
|| m_interface->isAlive() == false) {
|
||||
ENET_ERROR("Connection refused by SERVER ...");
|
||||
}
|
||||
}
|
||||
} while (m_redirectInProgress == true);
|
||||
}
|
||||
}
|
||||
|
||||
void enet::WebSocket::stop(bool _inThread) {
|
||||
ENET_DEBUG("Stop interface ...");
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
@@ -185,15 +184,18 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
ENET_VERBOSE("ReadRaw 2 [STOP]");
|
||||
return;
|
||||
}
|
||||
m_lastReceive = std::chrono::steady_clock::now();
|
||||
m_lastReceive = echrono::Steady::now();
|
||||
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);
|
||||
return;
|
||||
}
|
||||
int8_t size1 = 0;
|
||||
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 (_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
||||
ENET_ERROR("Protocol error occured ...");
|
||||
@@ -204,6 +206,12 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
}
|
||||
ENET_ERROR("Time out ... ==> not managed ...");
|
||||
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;
|
||||
}
|
||||
uint64_t totalSize = size1 & 0x7F;
|
||||
@@ -283,32 +291,32 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
// check opcode:
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_CLOSE) {
|
||||
// Close the conection by remote:
|
||||
ENET_INFO("Close connection by remote :");
|
||||
ENET_WARNING("Close connection by remote :");
|
||||
m_interface->stop(true);
|
||||
return;
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PING) {
|
||||
// Close the conection by remote:
|
||||
ENET_DEBUG("Receive a ping (send a pong)");
|
||||
ENET_WARNING("Receive a ping (send a pong)");
|
||||
controlPong();
|
||||
return;
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PONG) {
|
||||
// Close the conection by remote:
|
||||
ENET_DEBUG("Receive a pong");
|
||||
ENET_WARNING("Receive a pong");
|
||||
return;
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_TEXT) {
|
||||
// Close the conection by remote:
|
||||
ENET_DEBUG("Receive a Text(UTF-8) data " << m_buffer.size() << " Bytes");
|
||||
if (m_observer != nullptr) {
|
||||
ENET_WARNING("Receive a Text(UTF-8) data " << m_buffer.size() << " Bytes");
|
||||
if (m_observer != null) {
|
||||
m_observer(m_buffer, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_BINARY) {
|
||||
// Close the conection by remote:
|
||||
if (m_observer != nullptr) {
|
||||
if (m_observer != null) {
|
||||
m_observer(m_buffer, false);
|
||||
}
|
||||
return;
|
||||
@@ -316,8 +324,8 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
ENET_ERROR("ReadRaw [STOP] (no opcode manage ... " << int32_t(opcode & 0x0F));
|
||||
}
|
||||
|
||||
static std::string removeStartAndStopSpace(const std::string& _value) {
|
||||
std::string out;
|
||||
static etk::String removeStartAndStopSpace(const etk::String& _value) {
|
||||
etk::String out;
|
||||
out.reserve(_value.size());
|
||||
bool findSpace = false;
|
||||
for (auto &it : _value) {
|
||||
@@ -337,12 +345,12 @@ static std::string removeStartAndStopSpace(const std::string& _value) {
|
||||
|
||||
void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||
ememory::SharedPtr<enet::HttpServer> interface = ememory::dynamicPointerCast<enet::HttpServer>(m_interface);
|
||||
if (interface == nullptr) {
|
||||
if (interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
_data.display();
|
||||
if (_data.getType() != enet::HTTPReqType::GET) {
|
||||
if (_data.getType() != enet::HTTPReqType::HTTP_GET) {
|
||||
enet::HttpAnswer answer(enet::HTTPAnswerCode::c400_badRequest, "support only GET");
|
||||
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||
answer.setKey("Connection", "close");
|
||||
@@ -375,16 +383,29 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||
return;
|
||||
}
|
||||
// parse all protocols:
|
||||
std::vector<std::string> listProtocol;
|
||||
etk::Vector<etk::String> listProtocol;
|
||||
if (_data.getKey("Sec-WebSocket-Protocol") != "") {
|
||||
listProtocol = etk::split(_data.getKey("Sec-WebSocket-Protocol"),',');
|
||||
for (size_t iii=0; iii<listProtocol.size(); ++iii) {
|
||||
listProtocol[iii] = removeStartAndStopSpace(listProtocol[iii]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_observerUriCheck != nullptr) {
|
||||
if (m_observerUriCheck(_data.getUri(), listProtocol) == false) {
|
||||
if (m_observerUriCheck != null) {
|
||||
etk::String ret = m_observerUriCheck(_data.getUri(), listProtocol);
|
||||
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);
|
||||
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||
answer.setKey("Connection", "close");
|
||||
@@ -397,7 +418,7 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||
answer.setKey("Upgrade", "websocket");
|
||||
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);
|
||||
if (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) {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
_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) {
|
||||
ENET_ERROR("change protocol has not been accepted ... " << _data.getErrorCode() << " with message : " << _data.getHelp());
|
||||
m_interface->stop(true);
|
||||
@@ -444,15 +473,10 @@ bool enet::WebSocket::configHeader(bool _isString, bool _mask) {
|
||||
m_sendBuffer.clear();
|
||||
m_sendBuffer.resize(ZEUS_BASE_OFFSET_HEADER, 0);
|
||||
if (_mask == true) {
|
||||
std::random_device rd;
|
||||
// Engine
|
||||
std::mt19937 e2(rd());
|
||||
// Distribtuions
|
||||
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));
|
||||
m_dataMask[0] = uint8_t(etk::tool::urand(0,255));
|
||||
m_dataMask[1] = uint8_t(etk::tool::urand(0,255));
|
||||
m_dataMask[2] = uint8_t(etk::tool::urand(0,255));
|
||||
m_dataMask[3] = uint8_t(etk::tool::urand(0,255));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -465,7 +489,7 @@ int32_t enet::WebSocket::writeData(uint8_t* _data, int32_t _len) {
|
||||
}
|
||||
|
||||
int32_t enet::WebSocket::send() {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
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) {
|
||||
ethread::UniqueLock lock(m_mutex);
|
||||
if (configHeader(_isString, _mask) == false) {
|
||||
return -1;
|
||||
}
|
||||
@@ -522,39 +547,42 @@ int32_t enet::WebSocket::write(const void* _data, int32_t _len, bool _isString,
|
||||
}
|
||||
|
||||
void enet::WebSocket::controlPing() {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
ethread::UniqueLock lock(m_mutex);
|
||||
uint8_t header = enet::websocket::FLAG_FIN
|
||||
| enet::websocket::OPCODE_FRAME_PING;
|
||||
m_lastSend = std::chrono::steady_clock::now();
|
||||
m_lastSend = echrono::Steady::now();
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
header = 0;
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void enet::WebSocket::controlPong() {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
ethread::UniqueLock lock(m_mutex);
|
||||
uint8_t header = enet::websocket::FLAG_FIN
|
||||
| enet::websocket::OPCODE_FRAME_PONG;
|
||||
m_lastSend = std::chrono::steady_clock::now();
|
||||
m_lastSend = echrono::Steady::now();
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
header = 0;
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void enet::WebSocket::controlClose() {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
}
|
||||
ethread::UniqueLock lock(m_mutex);
|
||||
uint8_t header = enet::websocket::FLAG_FIN
|
||||
| enet::websocket::OPCODE_FRAME_CLOSE;
|
||||
m_lastSend = std::chrono::steady_clock::now();
|
||||
m_lastSend = echrono::Steady::now();
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
header = 0;
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
|
@@ -1,30 +1,33 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <enet/Http.h>
|
||||
#include <ememory/memory.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <enet/Http.hpp>
|
||||
#include <ememory/memory.hpp>
|
||||
#include <echrono/Steady.hpp>
|
||||
#include <etk/Vector.hpp>
|
||||
#include <etk/Map.hpp>
|
||||
|
||||
namespace enet {
|
||||
class WebSocket {
|
||||
protected:
|
||||
std::vector<uint8_t> m_sendBuffer;
|
||||
etk::Vector<uint8_t> m_sendBuffer;
|
||||
bool m_connectionValidate;
|
||||
ememory::SharedPtr<enet::Http> m_interface;
|
||||
std::vector<uint8_t> m_buffer;
|
||||
std::string m_checkKey;
|
||||
std::chrono::steady_clock::time_point m_lastReceive;
|
||||
std::chrono::steady_clock::time_point m_lastSend;
|
||||
etk::Vector<uint8_t> m_buffer;
|
||||
etk::String m_checkKey;
|
||||
echrono::Steady m_lastReceive;
|
||||
echrono::Steady m_lastSend;
|
||||
ethread::Mutex m_mutex;
|
||||
bool m_redirectInProgress = false;
|
||||
public:
|
||||
const std::chrono::steady_clock::time_point& getLastTimeReceive() {
|
||||
const echrono::Steady& getLastTimeReceive() {
|
||||
return m_lastReceive;
|
||||
}
|
||||
const std::chrono::steady_clock::time_point& getLastTimeSend() {
|
||||
const echrono::Steady& getLastTimeSend() {
|
||||
return m_lastSend;
|
||||
}
|
||||
public:
|
||||
@@ -32,10 +35,10 @@ namespace enet {
|
||||
WebSocket(enet::Tcp _connection, bool _isServer=false);
|
||||
void setInterface(enet::Tcp _connection, bool _isServer=false);
|
||||
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);
|
||||
bool isAlive() const {
|
||||
if (m_interface == nullptr) {
|
||||
if (m_interface == null) {
|
||||
return false;
|
||||
}
|
||||
return m_interface->isAlive();
|
||||
@@ -44,13 +47,19 @@ namespace enet {
|
||||
void onReceiveRequest(const enet::HttpRequest& _data);
|
||||
void onReceiveAnswer(const enet::HttpAnswer& _data);
|
||||
protected:
|
||||
std::string m_protocol;
|
||||
etk::String m_protocol;
|
||||
public:
|
||||
void setProtocol(const std::string& _protocol) {
|
||||
void setProtocol(const etk::String& _protocol) {
|
||||
m_protocol = _protocol;
|
||||
}
|
||||
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:
|
||||
Observer m_observer;
|
||||
public:
|
||||
@@ -61,8 +70,8 @@ namespace enet {
|
||||
* @param[in] _args Argument optinnal the user want to add.
|
||||
*/
|
||||
template<class CLASS_TYPE>
|
||||
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(std::vector<uint8_t>&, bool)) {
|
||||
m_observer = [=](std::vector<uint8_t>& _value, bool _isString){
|
||||
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(etk::Vector<uint8_t>&, bool)) {
|
||||
m_observer = [=](etk::Vector<uint8_t>& _value, bool _isString){
|
||||
(*_class.*_func)(_value, _isString);
|
||||
};
|
||||
}
|
||||
@@ -71,7 +80,15 @@ namespace enet {
|
||||
}
|
||||
// Only server:
|
||||
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:
|
||||
ObserverUriCheck m_observerUriCheck;
|
||||
public:
|
||||
@@ -82,8 +99,8 @@ namespace enet {
|
||||
* @param[in] _args Argument optinnal the user want to add.
|
||||
*/
|
||||
template<class CLASS_TYPE>
|
||||
void connectUri(CLASS_TYPE* _class, bool (CLASS_TYPE::*_func)(const std::string&, const std::vector<std::string>&)) {
|
||||
m_observerUriCheck = [=](const std::string& _value, const std::vector<std::string>& _protocols){
|
||||
void connectUri(CLASS_TYPE* _class, etk::String (CLASS_TYPE::*_func)(const etk::String&, const etk::Vector<etk::String>&)) {
|
||||
m_observerUriCheck = [=](const etk::String& _value, const etk::Vector<etk::String>& _protocols){
|
||||
return (*_class.*_func)(_value, _protocols);
|
||||
};
|
||||
}
|
||||
@@ -95,8 +112,20 @@ namespace enet {
|
||||
bool m_haveMask;
|
||||
uint8_t m_dataMask[4];
|
||||
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);
|
||||
/**
|
||||
* CWrite data in a temporary buffer ==> must lock external to prevent multiple simultaneous access
|
||||
*/
|
||||
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();
|
||||
/**
|
||||
* @brief Write a chunk of data on the socket
|
||||
@@ -104,8 +133,8 @@ namespace enet {
|
||||
* @param[in] _len Size that must be written socket
|
||||
* @return >0 byte size on the socket write
|
||||
* @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);
|
||||
/**
|
||||
* @brief Write a chunk of data on the socket
|
||||
@@ -114,7 +143,7 @@ namespace enet {
|
||||
* @return >0 byte size on the socket write
|
||||
* @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) {
|
||||
return 0;
|
||||
}
|
||||
@@ -131,7 +160,7 @@ namespace enet {
|
||||
* @return -1 an error occured.
|
||||
*/
|
||||
template <class T>
|
||||
int32_t write(const std::vector<T>& _data) {
|
||||
int32_t write(const etk::Vector<T>& _data) {
|
||||
if (_data.size() == 0) {
|
||||
return 0;
|
||||
}
|
@@ -1,10 +1,10 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <enet/debug.h>
|
||||
#include <enet/debug.hpp>
|
||||
|
||||
int32_t enet::getLogId() {
|
||||
static int32_t g_val = elog::registerInstance("enet");
|
||||
|
@@ -1,11 +1,11 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <elog/log.h>
|
||||
#include <elog/log.hpp>
|
||||
|
||||
namespace enet {
|
||||
int32_t getLogId();
|
54
enet/enet.cpp
Normal file
54
enet/enet.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/debug.hpp>
|
||||
|
||||
static bool& getInitSatatus() {
|
||||
static bool isInit = false;
|
||||
return isInit;
|
||||
}
|
||||
#ifdef __TARGET_OS__Windows
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
WSADATA wsaData;
|
||||
#endif
|
||||
|
||||
void enet::init(int _argc, const char** _argv) {
|
||||
for (int32_t iii=0; iii<_argc; ++iii) {
|
||||
etk::String value = _argv[iii];
|
||||
if (etk::start_with(value, "--enet") == true) {
|
||||
ENET_ERROR("Unknow parameter type: '" << value << "'");
|
||||
}
|
||||
}
|
||||
if (getInitSatatus() == false) {
|
||||
#ifdef __TARGET_OS__Windows
|
||||
// Initialize Winsock
|
||||
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if (iResult != 0) {
|
||||
ENET_ERROR("WSAStartup failed with error: " << iResult);
|
||||
}
|
||||
#endif
|
||||
getInitSatatus() = true;
|
||||
}
|
||||
}
|
||||
|
||||
void enet::unInit() {
|
||||
if (getInitSatatus() == false) {
|
||||
ENET_ERROR("Request UnInit of enent already done ...");
|
||||
} else {
|
||||
#ifdef __TARGET_OS__Windows
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
getInitSatatus() = false;
|
||||
}
|
||||
|
||||
|
||||
bool enet::isInit() {
|
||||
return getInitSatatus();
|
||||
}
|
||||
|
12
enet/enet.h
12
enet/enet.h
@@ -1,12 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <enet/Udp.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/Http.h>
|
||||
#include <enet/Ftp.h>
|
||||
|
34
enet/enet.hpp
Normal file
34
enet/enet.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <enet/Udp.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <enet/Ftp.hpp>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Main esvg namespace
|
||||
*/
|
||||
namespace enet {
|
||||
/**
|
||||
* @brief Initialize enet
|
||||
* @param[in] _argc Number of argument list
|
||||
* @param[in] _argv List of arguments
|
||||
*/
|
||||
void init(int _argc, const char** _argv);
|
||||
/**
|
||||
* @brief un-Initialize enet
|
||||
*/
|
||||
void unInit();
|
||||
/**
|
||||
* @brief Check if the library is initialized
|
||||
* @return bool value to chek if initialize ot not
|
||||
*/
|
||||
bool isInit();
|
||||
}
|
||||
|
100
enet/pourcentEncoding.cpp
Normal file
100
enet/pourcentEncoding.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#include <enet/pourcentEncoding.hpp>
|
||||
#include <enet/debug.hpp>
|
||||
#include <etk/types.hpp>
|
||||
#include <etk/String.hpp>
|
||||
|
||||
const etk::String hexData = "0123456789ABCDEF";
|
||||
|
||||
etk::String enet::pourcentEncode(const etk::String& _data) {
|
||||
etk::String out;
|
||||
for (auto &it : _data) {
|
||||
if ( (it >= 'a' && it <= 'z')
|
||||
|| (it >= 'A' && it <= 'Z')
|
||||
|| (it >= '0' && it <= '9')
|
||||
|| it == '-'
|
||||
|| it == '_'
|
||||
|| it == '.'
|
||||
|| it == '~') {
|
||||
out += it;
|
||||
} else {
|
||||
out += "%";
|
||||
out += hexData[(uint32_t(it)>>4)&0x0F];
|
||||
out += hexData[uint32_t(it)&0x0F];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static int32_t convertStringHexToInt(const char _value) {
|
||||
if (_value >= 'a' && _value <= 'z') {
|
||||
return int32_t(_value) - int32_t('a') + 10;
|
||||
}
|
||||
if (_value >= 'A' && _value <= 'Z') {
|
||||
return int32_t(_value) - int32_t('A') + 10;
|
||||
}
|
||||
if (_value >= '0' && _value <= '9') {
|
||||
return int32_t(_value) - int32_t('0');
|
||||
}
|
||||
ENET_ERROR("Not a hexadecimal Value: '" << _value << "'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
etk::String enet::pourcentDecode(const etk::String& _data) {
|
||||
etk::String out;
|
||||
for (size_t iii=0; iii<_data.size(); ++iii) {
|
||||
auto it = _data[iii];
|
||||
if (it == '%') {
|
||||
if (iii+2 < _data.size()) {
|
||||
auto val1 = convertStringHexToInt(_data[iii+1])<<4;
|
||||
val1 += convertStringHexToInt(_data[iii+2]);
|
||||
out += char(val1);
|
||||
iii += 2;
|
||||
} else {
|
||||
ENET_ERROR("can not convert pourcent ==> input size error: '" << _data << "'");
|
||||
return out;
|
||||
}
|
||||
} else {
|
||||
out += it;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
etk::String enet::pourcentUriEncode(const etk::Map<etk::String, etk::String>& _data) {
|
||||
etk::String out;
|
||||
for (auto &it: _data) {
|
||||
if (out.empty() == false) {
|
||||
out += "&";
|
||||
}
|
||||
out += enet::pourcentEncode(it.first);
|
||||
if (it.second.empty() == false) {
|
||||
out += "=";
|
||||
out += enet::pourcentEncode(it.second);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
etk::Map<etk::String, etk::String> enet::pourcentUriDecode(const etk::String& _data) {
|
||||
etk::Map<etk::String, etk::String> out;
|
||||
auto listElements = etk::split(_data, '&');
|
||||
for (auto &it : listElements) {
|
||||
if (it.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
auto offset = it.find('=');
|
||||
if (offset == etk::String::npos) {
|
||||
out.set(enet::pourcentDecode(it), "");
|
||||
continue;
|
||||
}
|
||||
out.set(enet::pourcentDecode(it.extract(0, offset)),
|
||||
enet::pourcentDecode(it.extract(offset+1, etk::String::npos)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
43
enet/pourcentEncoding.hpp
Normal file
43
enet/pourcentEncoding.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2014, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <etk/String.hpp>
|
||||
#include <etk/Map.hpp>
|
||||
|
||||
|
||||
namespace enet {
|
||||
/**
|
||||
* @brief Encode a string with transform the unvalid char in %XX.
|
||||
* @param[in] _data Raw string.
|
||||
* @return Encoded string.
|
||||
*/
|
||||
etk::String pourcentEncode(const etk::String& _data);
|
||||
|
||||
/**
|
||||
* @brief Decode a string with %XX with normal chars.
|
||||
* @param[in] _data Encoded string.
|
||||
* @return Raw string.
|
||||
*/
|
||||
etk::String pourcentDecode(const etk::String& _data);
|
||||
|
||||
/**
|
||||
* @brief Encode a map of string with %XX and "&" between element and = between key and value.
|
||||
* @param[in] _data Imput map to encode.
|
||||
* @return Encoded string.
|
||||
*/
|
||||
etk::String pourcentUriEncode(const etk::Map<etk::String, etk::String>& _data);
|
||||
|
||||
/**
|
||||
* @brief Encode a map of string with %XX and "&" between element and = between key and value.
|
||||
* @param[in] _data Encoded string like AAA=333&RRR=333&RRR
|
||||
* @return Te decoded map of values.
|
||||
*/
|
||||
etk::Map<etk::String, etk::String> pourcentUriDecode(const etk::String& _data);
|
||||
|
||||
}
|
||||
|
13
license.txt
13
license.txt
@@ -1,13 +0,0 @@
|
||||
Copyright enet Edouard DUPIN
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def get_desc():
|
||||
return "e-net TEST test software for enet"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,14 +24,17 @@ def get_compagny_name():
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_path(tools.get_current_path(__file__), export=True)
|
||||
my_module.add_depend(['enet', 'gtest', 'test-debug'])
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-client-http.cpp'
|
||||
])
|
||||
return my_module
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def get_desc():
|
||||
return "e-net TEST test software for enet"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,14 +24,17 @@ def get_compagny_name():
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_path(tools.get_current_path(__file__), export=True)
|
||||
my_module.add_depend(['enet', 'gtest', 'test-debug'])
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-client-websocket.cpp'
|
||||
])
|
||||
return my_module
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def get_desc():
|
||||
return "e-net TEST test software for enet"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,14 +24,17 @@ def get_compagny_name():
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_path(tools.get_current_path(__file__), export=True)
|
||||
my_module.add_depend(['enet', 'gtest', 'test-debug'])
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-client.cpp'
|
||||
])
|
||||
return my_module
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def get_desc():
|
||||
return "e-net TEST test software for enet"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,14 +24,17 @@ def get_compagny_name():
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_path(tools.get_current_path(__file__), export=True)
|
||||
my_module.add_depend(['enet', 'gtest', 'test-debug'])
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-server-http.cpp'
|
||||
])
|
||||
return my_module
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def get_desc():
|
||||
return "e-net TEST test software for enet"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,14 +24,17 @@ def get_compagny_name():
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_path(tools.get_current_path(__file__), export=True)
|
||||
my_module.add_depend(['enet', 'gtest', 'test-debug'])
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-server-websocket.cpp'
|
||||
])
|
||||
return my_module
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def get_desc():
|
||||
return "e-net TEST test software for enet"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,14 +24,17 @@ def get_compagny_name():
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_path(tools.get_current_path(__file__), export=True)
|
||||
my_module.add_depend(['enet', 'gtest', 'test-debug'])
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-server.cpp'
|
||||
])
|
||||
return my_module
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
45
lutin_enet-test.py
Normal file
45
lutin_enet-test.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/python
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
def get_type():
|
||||
return "BINARY"
|
||||
|
||||
def get_sub_type():
|
||||
return "TEST"
|
||||
|
||||
def get_desc():
|
||||
return "e-net TEST basic backend"
|
||||
|
||||
def get_licence():
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
|
||||
def get_compagny_name():
|
||||
return "atria-soft"
|
||||
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def configure(target, my_module):
|
||||
my_module.add_path(".")
|
||||
my_module.add_depend([
|
||||
'enet',
|
||||
'etest',
|
||||
'test-debug'
|
||||
])
|
||||
my_module.add_src_file([
|
||||
'test/main-test.cpp',
|
||||
'test/main-unit-pourcentEncoding.cpp'
|
||||
])
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.module as module
|
||||
import realog.debug as debug
|
||||
import lutin.tools as tools
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ def get_desc():
|
||||
return "TCP/UDP/HTTP/FTP interface"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
return "MPL-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
@@ -24,16 +24,17 @@ def get_maintainer():
|
||||
def get_version():
|
||||
return "version.txt"
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name, get_type())
|
||||
my_module.add_depend(['etk', 'ememory', 'algue'])
|
||||
my_module.add_src_file([
|
||||
'enet/debug.cpp'
|
||||
def configure(target, my_module):
|
||||
my_module.add_depend([
|
||||
'etk',
|
||||
'ememory',
|
||||
'algue',
|
||||
'ethread'
|
||||
])
|
||||
my_module.add_path(tools.get_current_path(__file__))
|
||||
if "Windows" in target.get_type():
|
||||
return my_module
|
||||
my_module.add_path(".")
|
||||
my_module.add_src_file([
|
||||
'enet/debug.cpp',
|
||||
'enet/enet.cpp',
|
||||
'enet/Udp.cpp',
|
||||
'enet/Tcp.cpp',
|
||||
'enet/TcpServer.cpp',
|
||||
@@ -41,18 +42,23 @@ def create(target, module_name):
|
||||
'enet/Http.cpp',
|
||||
'enet/Ftp.cpp',
|
||||
'enet/WebSocket.cpp',
|
||||
'enet/pourcentEncoding.cpp',
|
||||
])
|
||||
my_module.add_header_file([
|
||||
'enet/debug.h',
|
||||
'enet/Udp.h',
|
||||
'enet/Tcp.h',
|
||||
'enet/TcpServer.h',
|
||||
'enet/TcpClient.h',
|
||||
'enet/Http.h',
|
||||
'enet/Ftp.h',
|
||||
'enet/WebSocket.h',
|
||||
'enet/enet.hpp',
|
||||
'enet/debug.hpp',
|
||||
'enet/Udp.hpp',
|
||||
'enet/Tcp.hpp',
|
||||
'enet/TcpServer.hpp',
|
||||
'enet/TcpClient.hpp',
|
||||
'enet/Http.hpp',
|
||||
'enet/Ftp.hpp',
|
||||
'enet/WebSocket.hpp',
|
||||
'enet/pourcentEncoding.hpp',
|
||||
])
|
||||
return my_module
|
||||
if "Windows" in target.get_type():
|
||||
my_module.add_depend("ws2");
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
@@ -1,20 +1,21 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @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.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/TcpClient.h>
|
||||
#include <enet/Http.h>
|
||||
#include <etk/etk.h>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/TcpClient.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <etk/etk.hpp>
|
||||
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
#include <etk/stdTools.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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("data:" << (char*)&_data[0] << "");
|
||||
}
|
||||
@@ -22,8 +23,9 @@ namespace appl {
|
||||
|
||||
int main(int _argc, const char *_argv[]) {
|
||||
etk::init(_argc, _argv);
|
||||
enet::init(_argc, _argv);
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
etk::String data = _argv[iii];
|
||||
if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||
@@ -35,28 +37,23 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_INFO("==================================");
|
||||
TEST_INFO("== Test HTTP client ==");
|
||||
TEST_INFO("==================================");
|
||||
#ifndef __TARGET_OS__Windows
|
||||
// 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 ...
|
||||
|
||||
// Create a HTTP connection in Client mode
|
||||
enet::HttpClient connection(std::move(tcpConnection));
|
||||
enet::HttpClient connection(etk::move(tcpConnection));
|
||||
// Set callbacks:
|
||||
connection.connect(appl::onReceiveData);
|
||||
|
||||
// start http connection (the actual state is just TCP start ...)
|
||||
connection.start();
|
||||
enet::HttpRequest req(enet::HTTPReqType::GET);
|
||||
enet::HttpRequest req(enet::HTTPReqType::HTTP_GET);
|
||||
req.setUri("plop.txt");
|
||||
connection.setHeader(req);
|
||||
|
||||
while (connection.isAlive() == true) {
|
||||
usleep(100000);
|
||||
ethread::sleepMilliSeconds((100));
|
||||
}
|
||||
|
||||
#else
|
||||
TEST_CRITICAL("not implemented");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,21 +1,22 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @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.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/TcpClient.h>
|
||||
#include <enet/Http.h>
|
||||
#include <enet/WebSocket.h>
|
||||
#include <etk/etk.h>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/TcpClient.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <enet/WebSocket.hpp>
|
||||
#include <etk/etk.hpp>
|
||||
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
#include <etk/stdTools.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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");
|
||||
if (_isString == true) {
|
||||
_data.resize(_data.size()+1);
|
||||
@@ -29,8 +30,9 @@ namespace appl {
|
||||
|
||||
int main(int _argc, const char *_argv[]) {
|
||||
etk::init(_argc, _argv);
|
||||
enet::init(_argc, _argv);
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
etk::String data = _argv[iii];
|
||||
if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||
@@ -42,21 +44,20 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_INFO("==================================");
|
||||
TEST_INFO("== Test WebSocket client ==");
|
||||
TEST_INFO("==================================");
|
||||
#ifndef __TARGET_OS__Windows
|
||||
// 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 ...
|
||||
|
||||
// Create a HTTP connection in Client mode
|
||||
enet::WebSocket connection(std::move(tcpConnection), false);
|
||||
enet::WebSocket connection(etk::move(tcpConnection), false);
|
||||
// Set callbacks:
|
||||
connection.connect(appl::onReceiveData);
|
||||
|
||||
// start http connection (the actual state is just TCP start ...)
|
||||
std::vector<std::string> protocols;
|
||||
protocols.push_back("test1526/1.0");
|
||||
protocols.push_back("test1526/1.5");
|
||||
protocols.push_back("Hello");
|
||||
etk::Vector<etk::String> protocols;
|
||||
protocols.pushBack("test1526/1.0");
|
||||
protocols.pushBack("test1526/1.5");
|
||||
protocols.pushBack("Hello");
|
||||
connection.start("/plop.txt", protocols);
|
||||
|
||||
// send some data to play ...
|
||||
@@ -65,12 +66,8 @@ int main(int _argc, const char *_argv[]) {
|
||||
int32_t timeout = 20;
|
||||
while (connection.isAlive() == true
|
||||
&& timeout > 0) {
|
||||
usleep(100000);
|
||||
ethread::sleepMilliSeconds((100));
|
||||
timeout--;
|
||||
}
|
||||
|
||||
#else
|
||||
TEST_CRITICAL("not implemented");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,21 +1,22 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @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.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/TcpClient.h>
|
||||
#include <enet/Http.h>
|
||||
#include <etk/etk.h>
|
||||
|
||||
#include <etk/stdTools.h>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/TcpClient.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <etk/etk.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
int main(int _argc, const char *_argv[]) {
|
||||
etk::init(_argc, _argv);
|
||||
enet::init(_argc, _argv);
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
etk::String data = _argv[iii];
|
||||
if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||
@@ -27,22 +28,27 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_INFO("==================================");
|
||||
TEST_INFO("== Test TCP client ==");
|
||||
TEST_INFO("==================================");
|
||||
#ifndef __TARGET_OS__Windows
|
||||
// client mode ...
|
||||
// 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 ...");
|
||||
if (connection.getConnectionStatus() != enet::Tcp::status::link) {
|
||||
TEST_ERROR("can not link to the socket...");
|
||||
return -1;
|
||||
}
|
||||
int32_t iii = 0;
|
||||
int32_t delay = 200;
|
||||
while ( connection.getConnectionStatus() == enet::Tcp::status::link
|
||||
&& iii<10000) {
|
||||
char data[1024];
|
||||
int32_t len = connection.read(data, 1024);
|
||||
TEST_INFO("read len=" << len << " data='" << data << "'");
|
||||
//if (data[len-1] == '2') {
|
||||
ethread::sleepMilliSeconds((delay));
|
||||
delay--;
|
||||
if (delay == 0) {
|
||||
delay = 500;
|
||||
}
|
||||
int32_t lenWrite = connection.write("get pair value");
|
||||
TEST_INFO("write len=" << lenWrite);
|
||||
//}
|
||||
@@ -59,8 +65,5 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_ERROR("can not unlink to the socket...");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
TEST_CRITICAL("not implemented");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,29 +1,30 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @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.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/Http.h>
|
||||
#include <enet/TcpServer.h>
|
||||
#include <etk/etk.h>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <enet/TcpServer.hpp>
|
||||
#include <etk/etk.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <etk/stdTools.h>
|
||||
|
||||
#include <etk/stdTools.hpp>
|
||||
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");
|
||||
}
|
||||
void onReceiveHeader(enet::HttpServer* _interface, const enet::HttpRequest& _data) {
|
||||
TEST_INFO("Receive Header data:");
|
||||
_data.display();
|
||||
if (_data.getType() == enet::HTTPReqType::GET) {
|
||||
if (_data.getType() == enet::HTTPReqType::HTTP_GET) {
|
||||
if (_data.getUri() == "plop.txt") {
|
||||
enet::HttpAnswer answer(enet::HTTPAnswerCode::c200_ok);
|
||||
std::string data = "<html><head></head></body>coucou</body></html>";
|
||||
answer.setKey("Content-Length", etk::to_string(data.size()));
|
||||
etk::String data = "<html><head></head></body>coucou</body></html>";
|
||||
answer.setKey("Content-Length", etk::toString(data.size()));
|
||||
_interface->setHeader(answer);
|
||||
_interface->write(data);
|
||||
_interface->stop(true);
|
||||
@@ -39,8 +40,9 @@ namespace appl {
|
||||
|
||||
int main(int _argc, const char *_argv[]) {
|
||||
etk::init(_argc, _argv);
|
||||
enet::init(_argc, _argv);
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
etk::String data = _argv[iii];
|
||||
if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||
@@ -52,7 +54,6 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_INFO("==================================");
|
||||
TEST_INFO("== Test HTTP server ==");
|
||||
TEST_INFO("==================================");
|
||||
#ifndef __TARGET_OS__Windows
|
||||
//Wait on TCP connection:
|
||||
enet::TcpServer interface;
|
||||
// Configure server interface:
|
||||
@@ -61,16 +62,16 @@ int main(int _argc, const char *_argv[]) {
|
||||
// Start listening ...
|
||||
interface.link();
|
||||
// Wait a new connection ..
|
||||
enet::Tcp tcpConnection = std::move(interface.waitNext());
|
||||
enet::Tcp tcpConnection = etk::move(interface.waitNext());
|
||||
// Free Connected port
|
||||
interface.unlink();
|
||||
// TODO : Check if connection is valid ...
|
||||
|
||||
// Create a HTTP connection in Server mode
|
||||
enet::HttpServer connection(std::move(tcpConnection));
|
||||
enet::HttpServer connection(etk::move(tcpConnection));
|
||||
enet::HttpServer* tmp = &connection;
|
||||
// Set callbacks:
|
||||
connection.connect([=](std::vector<uint8_t>& _value){
|
||||
connection.connect([=](etk::Vector<uint8_t>& _value){
|
||||
appl::onReceiveData(tmp, _value);
|
||||
});
|
||||
connection.connectHeader([=](const enet::HttpRequest& _value){
|
||||
@@ -81,7 +82,7 @@ int main(int _argc, const char *_argv[]) {
|
||||
connection.start();
|
||||
|
||||
while (connection.isAlive() == true) {
|
||||
usleep(100000);
|
||||
ethread::sleepMilliSeconds((100));
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +97,8 @@ int main(int _argc, const char *_argv[]) {
|
||||
|
||||
TEST_INFO("----------------------------");
|
||||
TEST_INFO("POST data : ");
|
||||
std::map<std::string, std::string> values;
|
||||
values.insert(std::make_pair<std::string, std::string>("plop", "valuePlop"));
|
||||
etk::Map<etk::String, etk::String> values;
|
||||
values.insert(etk::makePair<etk::String, etk::String>("plop", "valuePlop"));
|
||||
if (connection.post("", values) == false) {
|
||||
TEST_ERROR("can not POST data...");
|
||||
return -1;
|
||||
@@ -106,14 +107,11 @@ int main(int _argc, const char *_argv[]) {
|
||||
|
||||
TEST_INFO("----------------------------");
|
||||
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...");
|
||||
return -1;
|
||||
}
|
||||
TEST_INFO("data : " << connection.dataString());
|
||||
*/
|
||||
#else
|
||||
TEST_CRITICAL("not implemented");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,20 +1,21 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @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.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/Http.h>
|
||||
#include <enet/WebSocket.h>
|
||||
#include <enet/TcpServer.h>
|
||||
#include <etk/etk.h>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <enet/WebSocket.hpp>
|
||||
#include <enet/TcpServer.hpp>
|
||||
#include <etk/etk.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <etk/stdTools.h>
|
||||
|
||||
#include <etk/stdTools.hpp>
|
||||
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");
|
||||
if (_isString == true) {
|
||||
_data.resize(_data.size()+1);
|
||||
@@ -25,7 +26,7 @@ namespace appl {
|
||||
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);
|
||||
for (auto &it : _protocols) {
|
||||
if (it == "test1526/1.5") {
|
||||
@@ -42,8 +43,9 @@ namespace appl {
|
||||
|
||||
int main(int _argc, const char *_argv[]) {
|
||||
etk::init(_argc, _argv);
|
||||
enet::init(_argc, _argv);
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
etk::String data = _argv[iii];
|
||||
if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||
@@ -55,7 +57,6 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_INFO("==================================");
|
||||
TEST_INFO("== Test WebSocket server ==");
|
||||
TEST_INFO("==================================");
|
||||
#ifndef __TARGET_OS__Windows
|
||||
//Wait on TCP connection:
|
||||
enet::TcpServer interface;
|
||||
// Configure server interface:
|
||||
@@ -64,19 +65,19 @@ int main(int _argc, const char *_argv[]) {
|
||||
// Start listening ...
|
||||
interface.link();
|
||||
// Wait a new connection ..
|
||||
enet::Tcp tcpConnection = std::move(interface.waitNext());
|
||||
enet::Tcp tcpConnection = etk::move(interface.waitNext());
|
||||
// Free Connected port
|
||||
interface.unlink();
|
||||
// TODO : Check if connection is valid ...
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -84,10 +85,7 @@ int main(int _argc, const char *_argv[]) {
|
||||
connection.start();
|
||||
|
||||
while (connection.isAlive() == true) {
|
||||
usleep(100000);
|
||||
ethread::sleepMilliSeconds((100));
|
||||
}
|
||||
#else
|
||||
TEST_CRITICAL("not implemented");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,21 +1,23 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @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.h>
|
||||
#include <enet/Tcp.h>
|
||||
#include <enet/Http.h>
|
||||
#include <etk/etk.h>
|
||||
#include <enet/TcpServer.h>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <enet/enet.hpp>
|
||||
#include <enet/Tcp.hpp>
|
||||
#include <enet/Http.hpp>
|
||||
#include <etk/etk.hpp>
|
||||
#include <enet/TcpServer.hpp>
|
||||
|
||||
#include <etk/stdTools.h>
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
int main(int _argc, const char *_argv[]) {
|
||||
etk::init(_argc, _argv);
|
||||
enet::init(_argc, _argv);
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
etk::String data = _argv[iii];
|
||||
if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
TEST_PRINT(etk::getApplicationName() << " - help : ");
|
||||
@@ -27,22 +29,21 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_INFO("==================================");
|
||||
TEST_INFO("== Test TCP server ==");
|
||||
TEST_INFO("==================================");
|
||||
#ifndef __TARGET_OS__Windows
|
||||
//Wait on TCP connection:
|
||||
enet::TcpServer interface;
|
||||
// Configure server interface:
|
||||
interface.setHostNane("127.0.0.1");
|
||||
interface.setPort(31235);
|
||||
interface.setPort(12345);
|
||||
// Start listening ...
|
||||
interface.link();
|
||||
// Wait a new connection ..
|
||||
enet::Tcp tcpConnection = std::move(interface.waitNext());
|
||||
enet::Tcp tcpConnection = etk::move(interface.waitNext());
|
||||
// Free Connected port
|
||||
interface.unlink();
|
||||
|
||||
int32_t iii = 0;
|
||||
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);
|
||||
char data[1024];
|
||||
len = tcpConnection.read(data, 1024);
|
||||
@@ -62,8 +63,5 @@ int main(int _argc, const char *_argv[]) {
|
||||
TEST_ERROR("can not unlink to the socket...");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
TEST_CRITICAL("not implemented");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
18
test/main-test.cpp
Normal file
18
test/main-test.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <test-debug/debug.hpp>
|
||||
|
||||
|
||||
#include <etest/etest.hpp>
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
// init test engine:
|
||||
etest::init(argc, argv);
|
||||
TEST_INFO("TEST ETK");
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
38
test/main-unit-pourcentEncoding.cpp
Normal file
38
test/main-unit-pourcentEncoding.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <test-debug/debug.hpp>
|
||||
#include <etest/etest.hpp>
|
||||
#include <enet/pourcentEncoding.hpp>
|
||||
|
||||
TEST(pourcentSerializer, stringEncode) {
|
||||
EXPECT_EQ(enet::pourcentEncode("hello"), "hello");
|
||||
EXPECT_EQ(enet::pourcentEncode("hello@plop plouf-_~"), "hello%40plop%20plouf-_~");
|
||||
}
|
||||
|
||||
TEST(pourcentSerializer, stringDecode) {
|
||||
EXPECT_EQ(enet::pourcentDecode("hello"), "hello");
|
||||
EXPECT_EQ(enet::pourcentDecode("hello%40plop%20plouf-_~"), "hello@plop plouf-_~");
|
||||
}
|
||||
|
||||
TEST(pourcentSerializer, mapEncode) {
|
||||
etk::Map<etk::String, etk::String> data;
|
||||
data.set("hello", "value1");
|
||||
data.set("simpleKey", "");
|
||||
data.set("special Key", "coucou");
|
||||
data.set("email", "you@example.com");
|
||||
EXPECT_EQ(enet::pourcentUriEncode(data), "email=you%40example.com&hello=value1&simpleKey&special%20Key=coucou");
|
||||
}
|
||||
|
||||
TEST(pourcentSerializer, mapDecode) {
|
||||
auto data = enet::pourcentUriDecode("hello=value1&simpleKey&special%20Key=coucou&email=you%40example.com");
|
||||
EXPECT_EQ(data.size(), 4);
|
||||
EXPECT_EQ(data["hello"], "value1");
|
||||
EXPECT_EQ(data["simpleKey"], "");
|
||||
EXPECT_EQ(data["special Key"], "coucou");
|
||||
EXPECT_EQ(data["email"], "you@example.com");
|
||||
}
|
@@ -1 +1 @@
|
||||
0.3.0
|
||||
1.0.0
|
Reference in New Issue
Block a user