Revert "Merge branch 'master' into JSON-128" - it was a b0rken merge.

This reverts commit a099d13101, reversing
changes made to 3eb0e3686b.
JSON-128
roker 2 years ago
parent a099d13101
commit 5dd6cba229

34
.gitignore vendored

@ -1,34 +0,0 @@
.DS_Store
*.o
*.Po
*.Plo
*.pc
*~
*.d
server/pep-json-server
server/servertest
server/unittests
server/*.a
server/prefix-config.cc
server/local.conf
server/*.d
server/json_spirit/*.d
build/
*.vcxproj.user
*.obj
*.exe
*.lib
build-windows/libevent/Release/*
build-windows/libevent/Debug/*
build-windows/pEpJSONServerAdapter/Release/*
build-windows/pEpJSONServerAdapter/Debug/*
server/pEp-mini-json-adapter
*.d.*
.??*.swp
tags

@ -0,0 +1,65 @@
syntax: glob
.DS_Store
*.o
*.Po
*.Plo
*.pc
*~
libevent-*-stable/Makefile
libevent-*-stable/config.h
libevent-*-stable/config.log
libevent-*-stable/config.status
libevent-*-stable/include/Makefile
libevent-*-stable/libtool
libevent-*-stable/sample/Makefile
libevent-*-stable/stamp-h1
libevent-*-stable/test/Makefile
libevent-*-stable/**/.libs/
libevent-*-stable/*.lo
libevent-*-stable/*.la
libevent-*-stable/autom4te.cache/
libevent-*-stable/include/event2/event-config.h
libevent-*-stable/sample/dns-example
libevent-*-stable/sample/event-test
libevent-*-stable/sample/hello-world
libevent-*-stable/sample/http-server
libevent-*-stable/sample/le-proxy
libevent-*-stable/sample/signal-test
libevent-*-stable/sample/time-test
libevent-*-stable/test/bench
libevent-*-stable/test/bench_cascade
libevent-*-stable/test/bench_http
libevent-*-stable/test/bench_httpclient
libevent-*-stable/test/regress
libevent-*-stable/test/rpcgen-attempted
libevent-*-stable/test/test-changelist
libevent-*-stable/test/test-eof
libevent-*-stable/test/test-init
libevent-*-stable/test/test-ratelim
libevent-*-stable/test/test-time
libevent-*-stable/test/test-weof
libevent-*-stable/build/
server/pep-json-server
server/servertest
server/unittests
server/*.a
server/prefix-config.cc
server/local.conf
server/*.d
server/json_spirit/*.d
build/
*.vcxproj.user
*.obj
*.exe
*.lib
build-windows/libevent/Release/*
build-windows/libevent/Debug/*
build-windows/pEpJSONServerAdapter/Release/*
build-windows/pEpJSONServerAdapter/Debug/*

@ -12,30 +12,29 @@ supported, Windows is about to follow. Newer versions should also work
(file a bug report if not) but are not in our main focus, yet.
## Dependencies
* C++ compiler: tested with g++ 4.8, 4.9, 8.3 and clang++ 2.8. Newer versions should work, too.
* C++ compiler: tested with g++ 4.8 and 4.9, and clang++ 2.8. Newer versions should work, too.
* GNU make
* libboost-thread-dev (tested with 1.58, 1.62, 1.67, 1.70 and 1.74)
* libboost-program-options-dev
* libboost-filesystem-dev
* [p≡p Engine](https://gitea.pep.foundation/pEp.foundation/pEpEngine/)
(which needs sequoia, a patched libetpan, libboost-system-dev)
* [libpEpAdapter](https://gitea.pep.foundation/pEp.foundation/libpEpAdapter/)
* [webserver](https://gitea.pep.foundation/fdik/webserver)
* libboost-thread-dev (tested with 1.58, 1.62 and 1.70)
* libboost-program-options-dev (tested with 1.58, 1.62 and 1.70)
* libboost-filesystem-dev (tested with 1.58, 1.62 and 1.70)
* libevent-dev 2.0.21 or 2.0.22 (or build from source, see below)
* [p≡p Engine](https://pep.foundation/dev/repos/pEpEngine/)
(which needs gpgme-thread, a patched libetpan, libboost-system-dev)
* [libpEpAdapter](https://pep.foundation/dev/repos/libpEpAdapter/)
* OSSP libuuid
## Building/Installing (Linux and macOS)
### Install the dependencies
Debian 9/10:
Debian 9:
~~~~~
apt install -y build-essential libboost-dev libboost-system-dev \
libboost-filesystem-dev libboost-program-options-dev \
libboost-thread-dev libgpgme-dev uuid-dev googletest \
apt install -y build-essential libboost1.62-dev libboost-system1.62-dev \
libboost-filesystem1.62-dev libboost-program-options1.62-dev \
libboost-thread1.62-dev libgpgme-dev uuid-dev googletest \
libevent-dev libevhtp-dev
~~~~~
macOS 10.12, 10.13, 10.14:
macOS 10.12:
Use homebrew or macports to install the required libraries.
@ -43,34 +42,26 @@ For more explicit instructions on how to do this with macports, see the
section below.
Build and install the pEp Engine. Instructions can be found here:
[the Engine's Readme](https://gitea.pep.foundation/pEp.foundation/pEpEngineREADME.md)
[https://cacert.pep.foundation/dev/repos/pEpEngine/file/ef23982e4744/README.md](https://cacert.pep.foundation/dev/repos/pEpEngine/file/ef23982e4744/README.md).
### Build and install libevent
### Build and install the 'webserver' project
It is recommended to use the libevent from your system's repository, if it contains the right version.
~~~~~
cd ~/code
git clone https://gitea.pep.foundation/fdik/webserver
cd webserver
(edit the Makefile for your $PREFIX etc.)
mkdir ~/code/json-ad
hg clone https://cacert.pep.foundation/dev/repos/pEpJSONServerAdapter/ ~/code/json-ad
cd ~/code/json-ad/libevent-2.0.22-stable
./configure --prefix="$HOME/code/json-ad/libevent-2.0.22-stable/build/" --disable-openssl
make
make install
~~~~~
### Build and install the JSON server
~~~~~
cd ~/code/json-ad/server
~~~~~
| :warning: FIXME: The following instructions refer to the old Makefile system that built a dynamically linked binary. This old Makefile was replaced by a hack to create a static binary. Unfortunately the config flexibility of the old Makefile system was removed in this change. |
| ------ |
| There is now also an ad-hoc created `Makefile.Linux`, which also can only be configured directly by editing the file. :-( |
| ------ |
| TODO: Re-create a more flexible build system with a `Makefile` (which is under revision control) and a `local.conf` (which is not, but contains your local-only config settings) |
| ------ |
Edit the build configuration to your needs in `./Makefile.conf`, or create a
`./local.conf` that sets any of the make variables documented in
`./Makefile.conf`.
@ -82,8 +73,7 @@ libevent.
Below are two sample `./local.conf` files, for orientation.
macOS 10.12, 10.13:
macOS 10.12:
~~~~~
PREFIX=$(HOME)/code/json-ad/build
@ -99,6 +89,9 @@ ENGINE_LIB=-L$(HOME)/code/engine/build/lib
ETPAN_INC=-I$(HOME)/code/libetpan/build/include
ETPAN_LIB=-L$(HOME)/code/libetpan/build/lib
EVENT_INC=-I$(HOME)/code/json-ad/libevent-2.0.22-stable/build/include
EVENT_LIB=-L$(HOME)/code/json-ad/libevent-2.0.22-stable/build/lib
GPGME_INC=-I$(HOME)/Cellar/gpgme/1.9.0_1/include
GPGME_LIB=-L$(HOME)/Cellar/gpgme/1.9.0_1/lib
@ -106,7 +99,7 @@ UUID_INC=-I$(HOME)/Cellar/ossp-uuid/1.6.2_2/include
UUID_LIB=-L$(HOME)/Cellar/ossp-uuid/1.6.2_2/lib
~~~~~
Debian 9/10:
Debian 9:
~~~~~
PREFIX=$(HOME)/code/json-ad/build
@ -119,6 +112,8 @@ ENGINE_LIB=-L$(HOME)/code/engine/build/lib
ETPAN_INC=-I$(HOME)/code/libetpan/build/include
ETPAN_LIB=-L$(HOME)/code/libetpan/build/lib
EVENT_INC=-I$(HOME)/code/json-ad/libevent-2.0.22-stable/build/include
EVENT_LIB=-L$(HOME)/code/json-ad/libevent-2.0.22-stable/build/lib
~~~~~
Now, build and install the server:
@ -170,19 +165,19 @@ the `Debug` or `Release` directory of the solution.
## Running the pEp JSON Adapter
You can use `make run` to start the server.
1. Run `./pEp-mini-json-adapter`. This creates a file that is readable only by the
current user (`~/.pEp/json-token`) and contains the address and
1. Run ./pep-json-server. This creates a file that is readable only by the
current user (~/.pEp/json-token-${USER}) and contains the address and
port the JSON adapter is listening on, normally 127.0.0.1:4223 and a
"security-token" that must be given in each function call to authenticate
you as the valid user.
```
./pEp-mini-json-adapter
./pep-json-server
```
2. Visit that address (normally `http://127.0.0.1:4223/`) in your
2. Visit that address (normally http://127.0.0.1:4223/) in your
JavaScript-enabled web browser to see the "JavaScript test client".
3. Call any function (`version()` or `get_gpg_path()` should work just
3. Call any function ("version()" or "get_gpg_path()" should work just
fine) with the correct security token.
## Using the p≡p JSON Adapter
@ -194,44 +189,22 @@ the adapter and its functions.
The JSON Server Adapter can be started on demand.
It checks automatically whether an instance for the same user on the machine
is already running and if yes it ends itself gracefully. (TODO!)
is already running and if yes it ends itself gracefully.
If there is no running server found the newly started server creates the
server token file and forks itself into background (if not prevented via
"-d" commandline switch).
### Multi-Client handling
The p≡p JSON server adapter supports multiple clients, communicating with the
server at the same time. Each client instance is identified by a client ID,
that the clients put into each JSON RPC request in the field "clientid".
The client ID is a UUID Version 4, created by the client at startup and has to
be stable while the client application runs. When the client restarts, a new
client ID should be created to avoid interferene with data from the old client
session.
### Session handling
The p≡p JSON server adapter stores data (e.g., a so called "config cache", see
next section) associated with each client ID. After a timeout period with no
JSON RPC calls and no open client connections these data are removed
automatically. Run the mini adapter with -h to see the compiled-in default
timeout value.
### PEP_SESSION handling
When using the p≡p engine, a `PEP_SESSION` is needed as parameter to many API
functions. The p≡p JSON Server Adapter automatically creates one session per
When using the p≡p engine, a session is needed to which any adapter can
connect. The p≡p JSON Server Adapter automatically creates one session per
HTTP client connection (and also closes that session automatically when the
client connections is closed). Therefore, the client does not need to take
care of the session management. However, the client should set up a [HTTP
care of the session management. However, the client has to set up a [HTTP
persistent
connection](https://en.wikipedia.org/wiki/HTTP_persistent_connection) to
minify session creation and destruction.
There is a configuration cache, that stores all `config_*()` calls and its
configured values. Whenever a new PEP_SESSION is needed for this client
(identified via its client ID, see previous section), all config values
are applied to this new session, too, before the session is used.
connection](https://en.wikipedia.org/wiki/HTTP_persistent_connection).
### API Principles
@ -290,105 +263,18 @@ Currently there are no range checks for numerical parameter types (e.g. a
JSON decimal number can hold a bigger value than the `int` parameter type of
a certain C function).
### JSON RPC Requests
The JSON Server Adapter offers its services via HTTP on the address and port
specified on command line. It offers a simple test HTML page on the root
URL.
The JSON RPC functions are POST requests to the path /ja/0.1/callFunction
and the JSON RPC data comes, as usual for POST requests, in the request body and
must be in UTF-8 without any BOM. The `Content-Type` of the request is not relevant.
Here is the body of an example request:
```
{
"id": 1001,
"jsonrpc": "2.0",
"security_token": "YSxxkNga0YUlkmdpUL6_qJuioicGK1wOC5sjGVG",
"method": "import_key",
"params": [
"4oW5PKhgY8XdvIYQiu+KaKnZYyP5UseHD1Sfjb8HpO75m/QT/FxFI………",
4444,
[
"OP"
]
]
}
```
another example:
```
{
"id": 1002,
"jsonrpc": "2.0",
"security_token": "YSxxkNga0YUlkmdpUL6_qJuioicGK1wOC5sjGVG",
"method": "myself",
"params": [
{
"user_id": "alice",
"username": "Alice in pEp land",
"address": "alice@pEp.lol",
"fpr": "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97"
}
]
}
```
Output parameters must be given, but their value is not relevant. The
JavaScript example test client fills the output values with a dummy array,
containing one string element "OP", just to ease debugging.
The result contains the return value and the values of the output parameters,
in reverse order:
Request:
```
{
"id": 1003,
"jsonrpc": "2.0",
"security_token": "YSxxkNga0YUlkmdpUL6_qJuioicGK1wOC5sjGVG",
"method": "get_languagelist",
"params": [
[
"OP"
]
]
}
```
Result:
```
{
"outParams": [
"\"en\",\"English\",\"I want to display the trustwords in English language\"……"
],
"return": {
"status": 0,
"hex": "0 \"PEP_STATUS_OK\""
}
}
```
### API Reference
An complete overview with all functions that are callable from the client
can be found in the [API Reference](pEp JSON Server Adapter/API Reference).
That API reference is a generated file (at irregular intervals) that shows the current API briefly.
That API reference is a generated file that shows the current API briefly.
There is also a (currently manually written) file that holts a copy of the
documentation from the Engine's header files: [API reference detail.md]
BEWARE: Because this file is not auto-generated, yet, it might be even more outdated!
Most of the callable functions are functions from the C API of the p≡p
Engine. They are described in detail, incl. pre- and post-conditions in
the appropriate C header files of the Engine, which are the authoritative source
of documentation in cases of doubt.
the appropriate C header files of the Engine.
### Authentication
@ -415,33 +301,12 @@ file that has user-only read permissions.
token".
### Callbacks / Event delivery
p≡p applications must register callback handlers at the Engine. At the moment
there are these callbacks:
* `PEP_STATUS messageToSend(message* msg)`
* `PEP_STATUS notifyHandshake(pEp_identity* self, pEp_identity* partner, sync_handshake_signal signal)`
The JSON adapter register its own functions at the Engine which propagate these
events to all connected clients.
The event propagation to the clients are done via long polling: Clients
call the function `pollForEvents()` that blocks until an event
from the Engine arrives. TODO: remove create_session(), use client ID instead?
It is planned to switch to use WebSockets: In fact this is also a type of
"long polling" and an open TCP connection, opened by the Client.
See: https://pep.foundation/jira/browse/JSON-128
## Extending / customizing
If you want to extend or customize the p≡p JSON Adapter, there are several
rules and definitions to take into account.
### API Functions
### Definitions
* The `FunctionMap function` in `ev_server.cc` defines which functions
are callable via the JSON-RPC interface. The existing entries show the
@ -490,15 +355,15 @@ number of parameters at the JSON side the same with the C side.
For In/Out parameters there exist two calling conventions for
call-by-pointer types:
1. caller allocates object and fills with input values, callee can only *change members*.
The C type of the parameter is usually `struct T*`. Use the wrapper `InOut<T*>`
1. caller allocates object and fills with input values, callee can only change members.
The C type of the parameter is usually `struct T*`. Use the wrapper `InOut<>`
for these parameters.
2. caller allocates object and fills with input values, callee might
change/reallocate the *whole object*. The C type of the parameter is
`struct T**`. Use the wrapper `InOutP<T*>` in these cases.
change/reallocate the whole object. The C type of the parameter is
`struct T**`. Use the wrapper `InOutP<>` in these cases.
`InOutP<T>` is also the right wrapper for in/out parameters of fundamental or
`InOutP<>` is also the right wrapper for in/out parameters of fundamental or
enum types due to the additional indirection in the C function call
signature.
@ -512,7 +377,7 @@ semantics described already above.
At the moment there exist two parameter type flags which are interpreted as
bitfield, so they can be combined:
* NoInput : This denotes a parameter at the C side that shall *not be exposed*
* NoInput : This flags a parameter at the C side that shall not be exposed
at the JSON side. So the value cannot be specified by the client, it is
provided by the JSON Server Adapter internally (e.g. for PEP_SESSION)
@ -523,7 +388,7 @@ bitfield, so they can be combined:
More flags will be added when different semantics will be needed.
#### Automatic parameter value generation
### Automatic parameter value generation
For some parameters or parameter combinations the JSON Server Adapter is
able to generate the values automatically either from the environment or
@ -531,11 +396,11 @@ from other parameters.
These automatic parameter value generators are supported at the moment:
##### In<c_string> and InLength
#### InLength
For functions that have a string parameter of type `const char*` followed by
a `size_t` that specifies the length of the string, the JSON Adapter can
calculate the value of that length parameter automatically, because in the
calculate the value of that length parameter automatically because in the
JSON API the lengths of strings are always known.
Moreover, the "length" that has to be given here means the length of the
@ -543,10 +408,6 @@ string seen by the C API side after processing of all JSON escaping
mechanisms as raw UTF-8 NFC string, so it might be difficult to calculate
that value at client side.
The "magic" is done inside the In<c_string> constructor that stores the string
length in its "Context", and the InLength<> constructore retrieves the value
from its "Context".
Example:
```
// C function declaration:
@ -581,24 +442,6 @@ Now the 2nd parameter is omitted:
}
```
### Embedding in other (desktop) adapters
The JSON Adapter can run as a stand-alone program (called the "mini-adapter") or
as part of another desktop adapter to enhance that adapter with a JSON-RPC interface.
For this the JSON Adapter has to co-operate with the desktop adapter in several ways:
* Startup, configuration and shutdown is managed by the desktop adapter.
* Handshake events and sync messages created by the pEpEngine have to be dispatched
to *all* connected clients, no matter whether they are JSON clients or "native"
clients of the desktop adapter. See "messageToSend" and "notifyHandshake" callbacks.
* The sync thread loop has to be managed by the desktop adapter. The libpEpAdapter
contains an example implementation for that.
* (something else?)
## TODOs

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{8CE78FD7-FE44-4F1F-B9A5-CB34186BBC56}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<NMakeBuildCommandLine>cd "$(ProjectDir)..\..\libevent-2.0.22-stable\" &amp;&amp; nmake -f Makefile.nmake</NMakeBuildCommandLine>
<NMakeOutput>libevent.lib</NMakeOutput>
<NMakePreprocessorDefinitions>WIN32;_DEBUG;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
<NMakeCleanCommandLine>cd "$(ProjectDir)..\..\libevent-2.0.22-stable\" &amp;&amp; nmake -f Makefile.nmake clean</NMakeCleanCommandLine>
<NMakeReBuildCommandLine>cd "$(ProjectDir)..\..\libevent-2.0.22-stable\" &amp;&amp; nmake -f Makefile.nmake /a</NMakeReBuildCommandLine>
<OutDir>..\..\libevent-2.0.22-stable</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<NMakeBuildCommandLine>cd "$(ProjectDir)..\..\libevent-2.0.22-stable\" &amp;&amp; nmake -f Makefile.nmake</NMakeBuildCommandLine>
<NMakeOutput>libevent.lib</NMakeOutput>
<NMakePreprocessorDefinitions>WIN32;NDEBUG;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
<NMakeCleanCommandLine>cd "$(ProjectDir)..\..\libevent-2.0.22-stable\" &amp;&amp; nmake -f Makefile.nmake clean</NMakeCleanCommandLine>
<NMakeReBuildCommandLine>cd "$(ProjectDir)..\..\libevent-2.0.22-stable\" &amp;&amp; nmake -f Makefile.nmake /a</NMakeReBuildCommandLine>
<OutDir>..\..\libevent-2.0.22-stable</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
</ItemDefinitionGroup>
<ItemGroup>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -3,28 +3,15 @@
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\webserver.cc">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\webserver.hh">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

@ -1,172 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{0d25734e-a71b-4536-8dc4-60e945382fc5}</ProjectGuid>
<RootNamespace>libpEpwebserver</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>libpEpWebserver</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\webserver.cc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\webserver.hh" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\pEpEngine\build-windows\pEpEngine.vcxproj">
<Project>{146e69f8-e1da-456a-b048-6dd29d9acf6b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\boost.1.72.0.0\build\boost.targets" Condition="Exists('..\..\..\..\packages\boost.1.72.0.0\build\boost.targets')" />
<Import Project="..\..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets" Condition="Exists('..\..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets')" />
<Import Project="..\..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets" Condition="Exists('..\..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets')" />
<Import Project="..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets" Condition="Exists('..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\boost.1.72.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost.1.72.0.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets'))" />
</Target>
</Project>

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.72.0.0" targetFramework="native" />
<package id="boost_date_time-vc142" version="1.72.0.0" targetFramework="native" />
<package id="boost_filesystem-vc142" version="1.72.0.0" targetFramework="native" />
<package id="boost_regex-vc142" version="1.72.0.0" targetFramework="native" />
</packages>

@ -1,268 +0,0 @@
// this file is derived from a boost::beast sample
#include <boost/beast/core.hpp>
#include <boost/filesystem.hpp>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
namespace fs = boost::filesystem;
#include "webserver.hh"
namespace pEp {
Webserver::Webserver(net::ip::address addr, unsigned short port, const std::string& doc_root)
: _ioc{1}
, _acceptor{_ioc, {addr, port}, false}
, _doc_root{doc_root}
, _generic_handler{}
, _port{port}
, _running{false}
{ }
beast::string_view Webserver::mime_type(beast::string_view path)
{
using beast::iequals;
auto const ext = [&path]
{
auto const pos = path.rfind(".");
if(pos == beast::string_view::npos)
return beast::string_view{};
return path.substr(pos);
}();
if(iequals(ext, ".htm")) return "text/html; charset=utf-8";
if(iequals(ext, ".html")) return "text/html; charset=utf-8";
if(iequals(ext, ".css")) return "text/css; charset=utf-8";
if(iequals(ext, ".txt")) return "text/plain; charset=utf-8";
if(iequals(ext, ".js")) return "application/javascript; charset=utf-8";
if(iequals(ext, ".json")) return "application/json; charset=utf-8";
if(iequals(ext, ".xml")) return "application/xml; charset=utf-8";
if(iequals(ext, ".png")) return "image/png";
if(iequals(ext, ".jpeg")) return "image/jpeg";
if(iequals(ext, ".jpg")) return "image/jpeg";
if(iequals(ext, ".gif")) return "image/gif";
if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon";
if(iequals(ext, ".tiff")) return "image/tiff";
if(iequals(ext, ".tif")) return "image/tiff";
if(iequals(ext, ".svg")) return "image/svg+xml; charset=utf-8";
if(iequals(ext, ".svgz")) return "image/svg+xml";
return "application/octet-stream";
}
void Webserver::add_url_handler(const std::string& url_regex, handler_t handler)
{
std::lock_guard< std::mutex > lock(_mtx);
_urls.emplace(url_regex, Handling{boost::regex(url_regex), handler});
}
void Webserver::remove_url_handler(const std::string& url_regex)
{
std::lock_guard< std::mutex > lock(_mtx);
_urls.erase(url_regex);
}
void Webserver::add_generic_url_handler(handler_t handler)
{
_generic_handler = handler;
}
void Webserver::remove_generic_url_handler()
{
_generic_handler = nullptr;
}
Webserver::response Webserver::create_status_response(const request& req, http::status status)
{
http::response< http::string_body > res{status, req.version()};
res.set(http::field::content_type, "text/html; charset=utf-8");
res.keep_alive(req.keep_alive());
std::stringstream s;
s << "<html><body>" << int(status) << " " << status << "</body></html>";
res.body() = s.str();
res.prepare_payload();
if (status != http::status::internal_server_error)
res.keep_alive(req.keep_alive());
return res;
}
Webserver* Webserver::probing_port_range(net::ip::address addr, unsigned short
start, unsigned short end, unsigned short& port, const std::string&
doc_root)
{
pEp::Webserver *web = nullptr;
for (port = start; port <= end; ++port) {
try {
web = new pEp::Webserver{addr, port, doc_root};
break;
}
catch (boost::system::system_error& err) {
}
}
return web;
}
void Webserver::deliver_status(tcp::socket *socket, const request& req, http::status status)
{
const response res { create_status_response(req, status) };
beast::error_code ec;
http::write(*socket, res, ec);
}
void Webserver::deliver_file(tcp::socket *socket, const request& req)
{
static boost::regex file{"/([\\w\\d]{1,100}\\.[\\w\\d]{1,4})"};
boost::cmatch m;
std::string d{req.target().data(), req.target().length()};
if (boost::regex_match(d.c_str(), m, file)) {
fs::path p{_doc_root};
p /= std::string(m[1]);
beast::error_code ec;
http::file_body::value_type body;
body.open(p.string().c_str(), beast::file_mode::scan, ec);
if (ec == beast::errc::no_such_file_or_directory) {
deliver_status(socket, req, http::status::not_found);
}
else if (ec) {
deliver_status(socket, req, http::status::internal_server_error);
}
else {
auto const size = body.size();
http::response<http::file_body> res{
std::piecewise_construct,
std::make_tuple(std::move(body)),
std::make_tuple(http::status::ok, req.version())};
res.set(http::field::content_type, mime_type(p.string().c_str()));
res.content_length(size);
res.keep_alive(req.keep_alive());
http::write(*socket, res, ec);
}
}
else {
deliver_status(socket, req, http::status::not_found);
}
}
Webserver::handler_t Webserver::find_handler(const request& req, boost::cmatch& m)
{
std::lock_guard< std::mutex > lock(_mtx);
for (auto it=_urls.begin(); it!=_urls.end(); ++it) {
std::string d{req.target().data(), req.target().length()};
if (boost::regex_match(d.c_str(), m, it->second.regex))
return it->second.handler;
}
return _generic_handler; // might be empty std::function!
}
void Webserver::do_session(tcp::socket *socket)
{
beast::error_code ec;
beast::flat_buffer buffer;
while (_running)
{
http::request_parser<http::string_body> parser;
parser.body_limit((std::numeric_limits<std::int32_t>::max)());
http::read(*socket, buffer, parser, ec);
if (ec) {
#ifndef NDEBUG
// This will print stuff like ...
// - end of stream
// - An established connection was aborted by the software in your host machine
// ... so don't be alarmed.
std::cerr << "pEpWebserver: " << ec.message() << "\n";
#endif
goto the_end;
}
http::request<http::string_body> req = parser.get();
const auto method = req.method();
switch (method)
{
case http::verb::post: // fall through
case http::verb::get:
{
boost::cmatch m;
Webserver::handler_t handler = find_handler(req, m);
if (handler) {
try{
const Webserver::response res = handler(m, req);
http::write(*socket, res, ec);
}
catch(...){
deliver_status(socket, req, http::status::internal_server_error);
}
}
else {
if(method == http::verb::get && !_doc_root.empty())
{
deliver_file(socket, req);
}else{
deliver_status(socket, req, http::status::not_found);
}
}
break;
}
default:
deliver_status(socket, req, http::status::method_not_allowed);
};
if (ec)
break;
}
the_end:
socket->shutdown(tcp::socket::shutdown_send, ec);
delete socket;
}
void Webserver::runner(Webserver *me)
{
while (me->_running)
{
tcp::socket* socket = new tcp::socket{me->_ioc};
me->_acceptor.accept(*socket);
std::function< void() > tf = [=]()
{
me->thread_init();
me->do_session(socket);
me->thread_done();
};
std::thread{tf}.detach();
}
}
void Webserver::run()
{
_running = true;
_runner = std::thread(runner, this);
}
void Webserver::shutdown()
{
_running = false;
}
};

@ -1,99 +0,0 @@
#pragma once
#include <string>
#include <unordered_map>
#include <thread>
#include <boost/asio/ip/tcp.hpp>
#include <boost/regex.hpp>
#include <boost/beast/http.hpp>
namespace pEp {
namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = boost::asio::ip::tcp;
// class Webserver
//
// when an URL handler is present it is called for each matching URL
// otherwise this server is searching for static files in doc_root
// only registered file types and no subdirectories are served for
// static files
//
// to deliver 404 return nullptr from handler
//
// this server is supporting GET for static files and POST for handlers
class Webserver {
public:
typedef boost::regex url_t;
typedef http::request< http::string_body > request;
typedef http::response< http::string_body > response;
typedef std::function< response(boost::cmatch, const request&) > handler_t;
private:
struct Handling {
boost::regex regex;
handler_t handler;
};
net::io_context _ioc;
tcp::acceptor _acceptor;
std::string _doc_root;
std::unordered_map< std::string, Handling > _urls;
handler_t _generic_handler;
unsigned short _port;
bool _running;
std::mutex _mtx;
std::thread _runner;
public:
// if doc_root is empty, don't deliver arbitrary files.
Webserver(net::ip::address addr, unsigned short port, const std::string& doc_root = "");
Webserver(const Webserver&) = delete;
Webserver& operator=(const Webserver&) = delete;
virtual ~Webserver() = default;
constexpr
int port() const noexcept { return _port; }
void add_url_handler (const std::string& url_regex, handler_t handler);
void remove_url_handler(const std::string& url_regex);
// the generic handler will be called if the URL does not match any registered handlers
void add_generic_url_handler (handler_t handler);
void remove_generic_url_handler();
void run();
void shutdown();
static beast::string_view mime_type(beast::string_view path);
static
response create_status_response(const request& req, http::status status);
static Webserver* probing_port_range(net::ip::address addr,
unsigned short start, unsigned short end, unsigned short&
port, const std::string& doc_root = "");
protected:
static void runner(Webserver *me);
void deliver_status(tcp::socket *socket, const request& req, http::status status);
void deliver_file (tcp::socket *socket, const request& req);
handler_t find_handler(const request& req, boost::cmatch& m);
// called at the beginning of a connection thread. Do nothing by default.
virtual void thread_init() {}
// called at the beginning of a connection thread. Do nothing by default.
virtual void thread_done() {}
// is called by run(), in a separate thread.
void do_session(tcp::socket *socket);
};
};

@ -55,16 +55,17 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_DEBUG;_LIB;DEBUG_ENABLED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\build-windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\WIN32-Code;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\include;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<UndefinePreprocessorDefinitions>%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions>
<AdditionalOptions>-D__PRETTY_FUNCTION__=__FUNCSIG__ %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\libevent-2.0.22-stable\</AdditionalLibraryDirectories>
<AdditionalDependencies>libevent.lib;libevent_core.lib;libevent_extras.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/NODEFAULTLIB:LIBCMT %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@ -78,7 +79,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\build-windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\WIN32-Code;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\include;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<UndefinePreprocessorDefinitions>%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions>
<AdditionalOptions>-D__PRETTY_FUNCTION__=__FUNCSIG__ %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
@ -87,7 +88,8 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\libevent-2.0.22-stable\</AdditionalLibraryDirectories>
<AdditionalDependencies>libevent.lib;libevent_core.lib;libevent_extras.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/NODEFAULTLIB:LIBCMT %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@ -116,24 +118,22 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\boost.1.72.0.0\build\boost.targets" Condition="Exists('..\..\..\packages\boost.1.72.0.0\build\boost.targets')" />
<Import Project="..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets" Condition="Exists('..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets')" />
<Import Project="..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets" Condition="Exists('..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets')" />
<Import Project="..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets" Condition="Exists('..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets')" />
<Import Project="..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets" Condition="Exists('..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets')" />
<Import Project="..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets" Condition="Exists('..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets')" />
<Import Project="..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets" Condition="Exists('..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" />
<Import Project="..\..\..\packages\boost.1.71.0.0\build\boost.targets" Condition="Exists('..\..\..\packages\boost.1.71.0.0\build\boost.targets')" />
<Import Project="..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets" Condition="Exists('..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets')" />
<Import Project="..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets" Condition="Exists('..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets')" />
<Import Project="..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets" Condition="Exists('..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets')" />
<Import Project="..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets" Condition="Exists('..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets')" />
<Import Project="..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets" Condition="Exists('..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\boost.1.72.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost.1.72.0.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost.1.71.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost.1.71.0.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets'))" />
</Target>
</Project>

@ -55,9 +55,9 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>JSON_ADAPTER_LIBRARY;DEBUG_ENABLED;WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\build-windows\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\WIN32-Code;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\include;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<UndefinePreprocessorDefinitions>%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions>
<AdditionalOptions>-D__PRETTY_FUNCTION__=__FUNCSIG__ %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
@ -75,9 +75,9 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>JSON_ADAPTER_LIBRARY;WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\build-windows\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\WIN32-Code;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable\include;$(SolutionDir)pEpJSONServerAdapter\libevent-2.0.22-stable;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<UndefinePreprocessorDefinitions>%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions>
<AdditionalOptions>-D__PRETTY_FUNCTION__=__FUNCSIG__ %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
@ -90,7 +90,6 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\server\adapter-library.hh" />
<ClInclude Include="..\..\server\base64.hh" />
<ClInclude Include="..\..\server\context.hh" />
<ClInclude Include="..\..\server\c_string.hh" />
@ -113,6 +112,7 @@
<ClInclude Include="..\..\server\logger_config.hh" />
<ClInclude Include="..\..\server\nfc.hh" />
<ClInclude Include="..\..\server\nfc_sets.hh" />
<ClInclude Include="..\..\server\nulllogger.hh" />
<ClInclude Include="..\..\server\pEp-types.hh" />
<ClInclude Include="..\..\server\pEp-utils-json.hh" />
<ClInclude Include="..\..\server\pEp-utils.hh" />
@ -120,14 +120,13 @@
<ClInclude Include="..\..\server\registry.hh" />
<ClInclude Include="..\..\server\security-token.hh" />
<ClInclude Include="..\..\server\server_version.hh" />
<ClInclude Include="..\..\server\session_registry.hh" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\server\base64.cc" />
<ClCompile Include="..\..\server\context.cc" />
<ClCompile Include="..\..\server\c_string.cc" />
<ClCompile Include="..\..\server\daemonize_windows.cc" />
<ClCompile Include="..\..\server\daemonize.cc" />
<ClCompile Include="..\..\server\ev_server.cc" />
<ClCompile Include="..\..\server\function_map.cc" />
<ClCompile Include="..\..\server\inout.cc" />
@ -139,48 +138,43 @@
<ClCompile Include="..\..\server\logger.cc" />
<ClCompile Include="..\..\server\nfc.cc" />
<ClCompile Include="..\..\server\nfc_sets.cc" />
<ClCompile Include="..\..\server\nulllogger.cc" />
<ClCompile Include="..\..\server\pEp-types.cc" />
<ClCompile Include="..\..\server\pEp-utils.cc" />
<ClCompile Include="..\..\server\prefix-config.cc" />
<ClCompile Include="..\..\server\registry.cc" />
<ClCompile Include="..\..\server\security-token.cc" />
<ClCompile Include="..\..\server\server_version.cc" />
<ClCompile Include="..\..\server\session_registry.cc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\libpEpAdapter\build-windows\libpEpAdapter.vcxproj">
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\libpEpAdapter\libpEpAdapter\libpEpAdapter.vcxproj">
<Project>{ec44fec9-2f3a-4a0c-b60e-0f22aa43ef58}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\pEpEngine\build-windows\pEpEngine.vcxproj">
<Project>{146e69f8-e1da-456a-b048-6dd29d9acf6b}</Project>
</ProjectReference>
<ProjectReference Include="..\pEp\libpEpwebserver\libpEpwebserver.vcxproj">
<Project>{0d25734e-a71b-4536-8dc4-60e945382fc5}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\boost.1.72.0.0\build\boost.targets" Condition="Exists('..\..\..\packages\boost.1.72.0.0\build\boost.targets')" />
<Import Project="..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets" Condition="Exists('..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets')" />
<Import Project="..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets" Condition="Exists('..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets')" />
<Import Project="..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets" Condition="Exists('..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets')" />
<Import Project="..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets" Condition="Exists('..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets')" />
<Import Project="..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets" Condition="Exists('..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets')" />
<Import Project="..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets" Condition="Exists('..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" />
<Import Project="..\..\..\packages\boost.1.71.0.0\build\boost.targets" Condition="Exists('..\..\..\packages\boost.1.71.0.0\build\boost.targets')" />
<Import Project="..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets" Condition="Exists('..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets')" />
<Import Project="..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets" Condition="Exists('..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets')" />
<Import Project="..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets" Condition="Exists('..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets')" />
<Import Project="..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets" Condition="Exists('..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets')" />
<Import Project="..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets" Condition="Exists('..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\boost.1.72.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost.1.72.0.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_chrono-vc142.1.72.0.0\build\boost_chrono-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_date_time-vc142.1.72.0.0\build\boost_date_time-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_filesystem-vc142.1.72.0.0\build\boost_filesystem-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_program_options-vc142.1.72.0.0\build\boost_program_options-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_thread-vc142.1.72.0.0\build\boost_thread-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost.1.71.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost.1.71.0.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_filesystem-vc142.1.71.0.0\build\boost_filesystem-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_thread-vc142.1.71.0.0\build\boost_thread-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_date_time-vc142.1.71.0.0\build\boost_date_time-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_chrono-vc142.1.71.0.0\build\boost_chrono-vc142.targets'))" />
<Error Condition="!Exists('..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\boost_program_options-vc142.1.71.0.0\build\boost_program_options-vc142.targets'))" />
</Target>
</Project>

@ -39,6 +39,9 @@
<ClInclude Include="..\..\server\pEp-types.hh">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\server\nulllogger.hh">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\server\nfc_sets.hh">
<Filter>Header Files</Filter>
</ClInclude>
@ -105,12 +108,6 @@
<ClInclude Include="..\..\server\json_spirit\json_spirit_writer_template.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\server\session_registry.hh">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\server\adapter-library.hh">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\server\server_version.cc">
@ -128,6 +125,9 @@
<ClCompile Include="..\..\server\pEp-types.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\server\nulllogger.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\server\nfc_sets.cc">
<Filter>Source Files</Filter>
</ClCompile>
@ -152,6 +152,9 @@
<ClCompile Include="..\..\server\ev_server.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\server\daemonize.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\server\context.cc">
<Filter>Source Files</Filter>
</ClCompile>
@ -173,12 +176,6 @@
<ClCompile Include="..\..\server\prefix-config.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\server\session_registry.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\server\daemonize_windows.cc">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

@ -1,151 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{84d7820e-599c-4ac9-b93c-ecedb0f4d213}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" />