* Initial commit

* Update README.md
This commit is contained in:
Ara Ayvazyan 2017-07-01 14:52:32 -07:00 коммит произвёл GitHub
Родитель 03a8c06660
Коммит cdcd3a6652
90 изменённых файлов: 7547 добавлений и 248 удалений

283
.gitignore поставляемый
Просмотреть файл

@ -1,252 +1,45 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
/ipch
*.gch
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Nuget packages
/packages
# Visual Studio files
/.vs
*.VC.opendb
*.VC.db
*.VC.VC.opendb
*.vcxproj.user
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Build folders
**/x64
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# Generated files
UnitTestsManaged/generated

6
.gitmodules поставляемый Normal file
Просмотреть файл

@ -0,0 +1,6 @@
[submodule "IPC"]
path = IPC
url = https://github.com/Microsoft/IPC
[submodule "bond"]
path = bond
url = https://github.com/Microsoft/bond.git

1
IPC Submodule

@ -0,0 +1 @@
Subproject commit 1f34d78408cd68e234305682a96f60ec5dd535af

52
IPC.Bond.sln Normal file
Просмотреть файл

@ -0,0 +1,52 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests", "UnitTests\Build\UnitTests.vcxproj", "{2A3B9657-1D10-4A71-AA21-62AD4106CED4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Native", "Native\Build\Native.vcxproj", "{2030ED0D-4667-4299-87CD-ACE298BDF56D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Interop", "Interop\Build\Interop.vcxproj", "{A13012C1-76DE-4D1D-A58B-2361D2BE8F65}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Managed", "Managed\Build\Managed.vcxproj", "{705098F7-93DC-4954-8165-FDDCD66231F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Transport", "Transport\Transport.csproj", "{BDAAAAAD-21A8-446E-840B-68718C49E7D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestsManaged", "UnitTestsManaged\UnitTestsManaged.csproj", "{BDFCB3AD-21A8-446E-840B-68718C49E7D4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A3B9657-1D10-4A71-AA21-62AD4106CED4}.Debug|x64.ActiveCfg = Debug|x64
{2A3B9657-1D10-4A71-AA21-62AD4106CED4}.Debug|x64.Build.0 = Debug|x64
{2A3B9657-1D10-4A71-AA21-62AD4106CED4}.Release|x64.ActiveCfg = Release|x64
{2A3B9657-1D10-4A71-AA21-62AD4106CED4}.Release|x64.Build.0 = Release|x64
{2030ED0D-4667-4299-87CD-ACE298BDF56D}.Debug|x64.ActiveCfg = Debug|x64
{2030ED0D-4667-4299-87CD-ACE298BDF56D}.Debug|x64.Build.0 = Debug|x64
{2030ED0D-4667-4299-87CD-ACE298BDF56D}.Release|x64.ActiveCfg = Release|x64
{2030ED0D-4667-4299-87CD-ACE298BDF56D}.Release|x64.Build.0 = Release|x64
{A13012C1-76DE-4D1D-A58B-2361D2BE8F65}.Debug|x64.ActiveCfg = Debug|x64
{A13012C1-76DE-4D1D-A58B-2361D2BE8F65}.Debug|x64.Build.0 = Debug|x64
{A13012C1-76DE-4D1D-A58B-2361D2BE8F65}.Release|x64.ActiveCfg = Release|x64
{A13012C1-76DE-4D1D-A58B-2361D2BE8F65}.Release|x64.Build.0 = Release|x64
{705098F7-93DC-4954-8165-FDDCD66231F0}.Debug|x64.ActiveCfg = Debug|x64
{705098F7-93DC-4954-8165-FDDCD66231F0}.Debug|x64.Build.0 = Debug|x64
{705098F7-93DC-4954-8165-FDDCD66231F0}.Release|x64.ActiveCfg = Release|x64
{705098F7-93DC-4954-8165-FDDCD66231F0}.Release|x64.Build.0 = Release|x64
{BDAAAAAD-21A8-446E-840B-68718C49E7D4}.Debug|x64.ActiveCfg = Debug|x64
{BDAAAAAD-21A8-446E-840B-68718C49E7D4}.Debug|x64.Build.0 = Debug|x64
{BDAAAAAD-21A8-446E-840B-68718C49E7D4}.Release|x64.ActiveCfg = Release|x64
{BDAAAAAD-21A8-446E-840B-68718C49E7D4}.Release|x64.Build.0 = Release|x64
{BDFCB3AD-21A8-446E-840B-68718C49E7D4}.Debug|x64.ActiveCfg = Debug|x64
{BDFCB3AD-21A8-446E-840B-68718C49E7D4}.Debug|x64.Build.0 = Debug|x64
{BDFCB3AD-21A8-446E-840B-68718C49E7D4}.Release|x64.ActiveCfg = Release|x64
{BDFCB3AD-21A8-446E-840B-68718C49E7D4}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Двоичные данные
IPC.Bond.snk Normal file

Двоичный файл не отображается.

75
Inc/IPC/Bond/Accept.h Normal file
Просмотреть файл

@ -0,0 +1,75 @@
#pragma once
#include <IPC/detail/Accept.h>
#include <IPC/Policies/ErrorHandler.h>
#include <IPC/ComponentCollection.h>
#include "Acceptor.h"
#include "Client.h"
#include "Server.h"
#include "DefaultTraits.h"
#include <bond/core/bond_const_enum.h>
#include <memory>
namespace IPC
{
namespace Bond
{
template <typename Request, typename Response, typename Traits = DefaultTraits, typename HandlerFactory, typename ErrorHandler = typename Traits::ErrorHandler>
auto AcceptServers(
const char* name,
HandlerFactory&& handlerFactory,
bond::ProtocolType protocol = bond::ProtocolType::COMPACT_PROTOCOL,
bool marshal = true,
ChannelSettings<Traits> channelSettings = {},
std::size_t minBlobSize = 0,
std::size_t hostInfoMemorySize = 0,
ErrorHandler&& errorHandler = {})
{
return IPC::detail::Accept<ServerAcceptor<Request, Response, Traits>>(
name,
std::make_shared<ServerCollection<Server<Request, Response, Traits>>>(),
[protocol, marshal, minBlobSize, handlerFactory = std::forward<HandlerFactory>(handlerFactory)](auto&& connection, auto&& closeHandler) mutable
{
return MakeServer<Request, Response, Traits>(
std::move(connection), handlerFactory, std::forward<decltype(closeHandler)>(closeHandler), protocol, marshal, minBlobSize);
},
std::forward<ErrorHandler>(errorHandler),
std::move(channelSettings),
hostInfoMemorySize);
}
template <typename Request, typename Response, typename Traits = DefaultTraits, typename ErrorHandler = typename Traits::ErrorHandler>
auto AcceptClients(
const char* name,
bond::ProtocolType protocol = bond::ProtocolType::COMPACT_PROTOCOL,
bool marshal = true,
ChannelSettings<Traits> channelSettings = {},
std::size_t minBlobSize = 0,
std::size_t hostInfoMemorySize = 0,
ErrorHandler&& errorHandler = {},
typename Traits::TransactionManagerFactory transactionManagerFactory = {})
{
using Client = Client<Request, Response, Traits>;
return IPC::detail::Accept<ClientAcceptor<Request, Response, Traits>>(
name,
std::make_shared<ClientCollection<Client>>(),
[protocol, marshal, minBlobSize, transactionManagerFactory = std::move(transactionManagerFactory)](auto&& connection, auto&& closeHandler)
{
return MakeClient<Request, Response, Traits>(
std::move(connection),
std::forward<decltype(closeHandler)>(closeHandler),
protocol,
marshal,
minBlobSize,
transactionManagerFactory(IPC::detail::Identity<typename Client::TransactionManager>{}));
},
std::forward<ErrorHandler>(errorHandler),
std::move(channelSettings),
hostInfoMemorySize);
}
} // Bond
} // IPC

19
Inc/IPC/Bond/Acceptor.h Normal file
Просмотреть файл

@ -0,0 +1,19 @@
#pragma once
#include <IPC/Acceptor.h>
#include "detail/ComponentBase.h"
#include "DefaultTraits.h"
namespace IPC
{
namespace Bond
{
template <typename Request, typename Response, typename Traits = DefaultTraits>
using ClientAcceptor = detail::BufferComponent<ClientAcceptor, Request, Response, Traits>;
template <typename Request, typename Response, typename Traits = DefaultTraits>
using ServerAcceptor = detail::BufferComponent<ServerAcceptor, Request, Response, Traits>;
} // Bond
} // IPC

43
Inc/IPC/Bond/BlobCast.h Normal file
Просмотреть файл

@ -0,0 +1,43 @@
#pragma once
#include "detail/BlobHolder.h"
#include <type_traits>
#ifndef NDEBUG
#include <IPC/SharedMemory.h>
#endif
namespace IPC
{
namespace Bond
{
template <typename Blob>
bond::blob BlobCast(Blob&& from, std::shared_ptr<SharedMemory> memory)
{
auto data = from.data();
auto size = from.size();
assert(memory && memory->Contains(data) && memory->Contains(data + size - 1));
return{
boost::shared_ptr<const char[]>{ data, detail::BlobHolder<std::decay_t<Blob>>{ std::forward<Blob>(from), std::move(memory) } },
static_cast<std::uint32_t>(size) };
}
template <typename Blob>
Blob BlobCast(const bond::blob& from)
{
if (auto deleter = boost::get_deleter<detail::BlobHolder<Blob>>(bond::blob_cast<detail::BlobHook>(from)))
{
const auto& blob = deleter->m_blob;
assert(blob);
return blob.GetRange(std::distance(blob.data(), from.content()), from.size());
}
return{};
}
} // Bond
} // IPC

368
Inc/IPC/Bond/BufferPool.h Normal file
Просмотреть файл

@ -0,0 +1,368 @@
#pragma once
#include "BufferPoolFwd.h"
#include "IPC/SharedMemory.h"
#include "IPC/detail/LockFree/Queue.h"
#include <boost/interprocess/containers/vector.hpp>
namespace IPC
{
namespace Bond
{
template <template <typename> typename QueueT>
class BufferPool<QueueT>::Impl
{
public:
using Queue = QueueT<SharedMemory::SharedPtr<Data>>;
explicit Impl(std::shared_ptr<SharedMemory> memory)
: m_memory{ std::move(memory) },
m_queue{ m_memory->MakeShared<Queue>(anonymous_instance, m_memory->GetAllocator<char>()) }
{}
SharedMemory::SharedPtr<Data> Take()
{
if (auto data = m_queue->Pop())
{
return std::move(*data);
}
return m_memory->MakeShared<Data>(anonymous_instance, m_memory->GetAllocator<char>());
}
const auto& GetQueue() const
{
return m_queue;
}
const auto& GetMemory() const
{
return m_memory;
}
private:
std::shared_ptr<SharedMemory> m_memory;
SharedMemory::SharedPtr<Queue> m_queue;
};
template <template <typename> typename QueueT>
struct BufferPool<QueueT>::Data
{
explicit Data(const SharedMemory::Allocator<char>& allocator)
: m_blob{ allocator },
m_buffer{ allocator }
{}
boost::interprocess::vector<char, SharedMemory::Allocator<char>> m_blob;
boost::interprocess::vector<ConstBlob, SharedMemory::Allocator<ConstBlob>> m_buffer;
};
template <template <typename> typename QueueT>
class BufferPool<QueueT>::ItemBase
{
public:
~ItemBase()
{
if (m_data.unique())
{
m_data->m_blob.clear();
m_data->m_buffer.clear();
m_queue->Push(std::move(m_data));
}
}
explicit operator bool() const
{
return m_data && m_queue;
}
protected:
ItemBase() = default;
ItemBase(SharedMemory::SharedPtr<Data> data, SharedMemory::SharedPtr<typename Impl::Queue> queue)
: m_data{ std::move(data) },
m_queue{ std::move(queue) }
{}
const auto& GetBlob() const
{
return m_data->m_blob;
}
auto& GetBlob()
{
return m_data->m_blob;
}
const auto& GetBuffer() const
{
return m_data->m_buffer;
}
auto& GetBuffer()
{
return m_data->m_buffer;
}
bool operator==(const ItemBase& other) const
{
return m_data == other.m_data && m_queue == other.m_queue;
}
private:
SharedMemory::SharedPtr<Data> m_data;
SharedMemory::SharedPtr<typename Impl::Queue> m_queue;
};
template <template <typename> typename QueueT>
class BufferPool<QueueT>::Blob : public ItemBase
{
friend BufferPool;
using ItemBase::ItemBase;
public:
Blob() = default;
Blob(const Blob& other) = delete;
Blob& operator=(const Blob& other) = delete;
Blob(Blob&& other) = default;
Blob& operator=(Blob&& other) = default;
decltype(auto) operator*() const
{
return this->GetBlob();
}
decltype(auto) operator*()
{
return this->GetBlob();
}
auto operator->() const
{
return &this->GetBlob();
}
auto operator->()
{
return &this->GetBlob();
}
};
template <template <typename> typename QueueT>
class BufferPool<QueueT>::ConstBlob : public ItemBase
{
using Iterator = decltype(std::declval<Data>().m_blob.cbegin());
public:
ConstBlob() = default;
ConstBlob(const Blob& blob)
: ConstBlob{ blob, blob->begin(), blob->end() }
{}
auto begin() const
{
return m_begin;
}
auto end() const
{
return m_end;
}
std::size_t size() const
{
return std::distance(m_begin, m_end);
}
const char* data() const
{
return std::addressof(*m_begin);
}
ConstBlob GetRange(std::size_t offset, std::size_t count) const
{
if (offset + count > size())
{
throw std::out_of_range{ "Out of buffer range." };
}
auto begin = std::next(m_begin, offset);
return{ *this, begin, std::next(begin, count) };
}
private:
ConstBlob(ItemBase blob, Iterator begin, Iterator end)
: ItemBase{ std::move(blob) },
m_begin{ begin },
m_end{ end }
{}
Iterator m_begin{};
Iterator m_end{};
};
template <template <typename> typename QueueT>
class BufferPool<QueueT>::Buffer : public ItemBase
{
friend BufferPool;
using ItemBase::ItemBase;
public:
Buffer() = default;
Buffer(const Buffer& other) = delete;
Buffer& operator=(const Buffer& other) = delete;
Buffer(Buffer&& other) = default;
Buffer& operator=(Buffer&& other) = default;
decltype(auto) operator*() const
{
return this->GetBuffer();
}
decltype(auto) operator*()
{
return this->GetBuffer();
}
auto operator->() const
{
return &this->GetBuffer();
}
auto operator->()
{
return &this->GetBuffer();
}
};
template <template <typename> typename QueueT>
class BufferPool<QueueT>::ConstBuffer : public ItemBase
{
using BlobIterator = decltype(std::declval<Data>().m_buffer.cbegin());
public:
struct Range
{
Range() = default;
Range(ConstBuffer buffer, BlobIterator firstBlob, std::size_t firstOffset, BlobIterator lastBlob, std::size_t lastOffset)
: m_firstBlob{ std::move(firstBlob) },
m_firstOffset{ firstOffset },
m_lastBlob{ std::move(lastBlob) },
m_lastOffset{ lastOffset },
m_buffer{ std::move(buffer) }
{}
bool IsEmpty() const
{
return m_firstBlob == m_lastBlob && m_firstOffset == m_lastOffset;
}
BlobIterator m_firstBlob;
std::size_t m_firstOffset{ 0 };
BlobIterator m_lastBlob;
std::size_t m_lastOffset{ 0 };
ConstBuffer m_buffer;
};
ConstBuffer() = default;
ConstBuffer(Buffer buffer)
: ItemBase{ std::move(buffer) }
{}
auto begin() const
{
return this->GetBuffer().begin();
}
auto end() const
{
return this->GetBuffer().end();
}
std::size_t size() const
{
std::size_t size = 0;
for (const auto& blob : this->GetBuffer())
{
size += blob.size();
}
return size;
}
bool operator==(const ConstBuffer& other) const
{
return ItemBase::operator==(other);
}
};
template <template <typename> typename QueueT>
BufferPool<QueueT>::BufferPool(std::shared_ptr<SharedMemory> memory)
: m_impl{ std::make_shared<Impl>(std::move(memory)) }
{}
template <template <typename> typename QueueT>
auto BufferPool<QueueT>::TakeBlob() -> Blob
{
return{ m_impl->Take(), m_impl->GetQueue() };
}
template <template <typename> typename QueueT>
auto BufferPool<QueueT>::TakeBuffer() -> Buffer
{
return{ m_impl->Take(), m_impl->GetQueue() };
}
template <template <typename> typename QueueT>
const std::shared_ptr<SharedMemory>& BufferPool<QueueT>::GetMemory() const
{
return m_impl->GetMemory();
}
namespace detail
{
template <typename T>
class DefaultBufferPoolQueue : public IPC::detail::LockFree::Queue<T, SharedMemory::Allocator<char>>
{
public:
using Queue::Queue;
};
template <typename BufferPool>
class ConstBuffer : public BufferPool::ConstBuffer
{
public:
using BufferPool::ConstBuffer::ConstBuffer;
ConstBuffer() = default;
ConstBuffer(const typename BufferPool::ConstBuffer& buffer)
: BufferPool::ConstBuffer{ buffer }
{}
};
} // detail
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,57 @@
#pragma once
#include <memory>
namespace IPC
{
class SharedMemory;
namespace Bond
{
template <template <typename> typename QueueT>
class BufferPool
{
public:
class Blob;
class ConstBlob;
class Buffer;
class ConstBuffer;
explicit BufferPool(std::shared_ptr<SharedMemory> memory);
Blob TakeBlob();
Buffer TakeBuffer();
const std::shared_ptr<SharedMemory>& GetMemory() const;
private:
struct Data;
class ItemBase;
class Impl;
std::shared_ptr<Impl> m_impl;
};
namespace detail
{
template <typename T>
class DefaultBufferPoolQueue;
template <typename BufferPool>
class ConstBuffer;
} // detail
using DefaultBufferPool = BufferPool<detail::DefaultBufferPoolQueue>;
using DefaultConstBuffer = detail::ConstBuffer<DefaultBufferPool>;
} // Bond
} // IPC

85
Inc/IPC/Bond/Client.h Normal file
Просмотреть файл

@ -0,0 +1,85 @@
#pragma once
#include "detail/ComponentBase.h"
#include <IPC/Client.h>
#include "DefaultTraits.h"
#include <bond/core/bond_const_enum.h>
namespace IPC
{
namespace Bond
{
template <typename Request, typename Response, typename Traits = DefaultTraits>
class Client : public detail::ComponentBase<IPC::Client, Request, Response, Traits>
{
using Base = detail::ComponentBase<IPC::Client, Request, Response, Traits>;
public:
template <typename CloseHandler>
Client(
typename Base::BufferPoolHolder pools,
typename Base::Serializer serializer,
std::unique_ptr<typename Base::Connection> connection,
CloseHandler&& closeHandler,
typename Base::TransactionManager transactionManager = {})
: Base{ std::move(pools), std::move(serializer), std::move(connection), std::forward<CloseHandler>(closeHandler), std::move(transactionManager) }
{}
template <typename Callback, typename... TransactionArgs, typename U = Response, std::enable_if_t<!std::is_void<U>::value>* = nullptr,
decltype(std::declval<Callback>()(std::declval<std::future<U>>()))* = nullptr>
void operator()(const Request& request, Callback&& callback, TransactionArgs&&... transactionArgs)
{
Base::operator()(
this->Serialize(request),
[serializer = static_cast<typename Base::Serializer&>(*this), callback = std::forward<Callback>(callback)](typename Traits::BufferPool::ConstBuffer&& buffer) mutable
{
callback(serializer.template Deserialize<Response>(std::move(buffer)));
},
std::forward<TransactionArgs>(transactionArgs)...);
}
template <typename U = Response, std::enable_if_t<std::is_void<U>::value>* = nullptr>
void operator()(const Request& request)
{
Base::operator()(this->Serialize(request));
}
template <typename... TransactionArgs, typename U = Response, std::enable_if_t<!std::is_void<U>::value>* = nullptr>
std::future<Response> operator()(const Request& request, TransactionArgs&&... transactionArgs)
{
std::packaged_task<Response(typename Traits::BufferPool::ConstBuffer&&)> callback{
[serializer = static_cast<typename Base::Serializer&>(*this)](typename Traits::BufferPool::ConstBuffer&& buffer) mutable
{
Response response;
serializer.Deserialize(std::move(buffer), response);
return response;
} };
auto result = callback.get_future();
Base::operator()(this->Serialize(request), std::move(callback), std::forward<TransactionArgs>(transactionArgs)...);
return result;
}
};
template <typename Request, typename Response, typename Traits = DefaultTraits, typename CloseHandler>
auto MakeClient(
std::unique_ptr<typename Client<Request, Response, Traits>::Connection> connection,
CloseHandler&& closeHandler,
bond::ProtocolType protocol = bond::ProtocolType::COMPACT_PROTOCOL,
bool marshal = true,
std::size_t minBlobSize = 0,
typename Client<Request, Response, Traits>::TransactionManager transactionManager = {})
{
auto pools = detail::MakeBufferPoolHolder<typename Traits::BufferPool>(*connection);
typename Traits::Serializer serializer{ protocol, marshal, pools.GetOutputPool(), pools.GetInputPool()->GetMemory(), minBlobSize };
return std::make_unique<Client<Request, Response, Traits>>(
std::move(pools), std::move(serializer), std::move(connection), std::forward<CloseHandler>(closeHandler), std::move(transactionManager));
}
} // Bond
} // IPC

88
Inc/IPC/Bond/Connect.h Normal file
Просмотреть файл

@ -0,0 +1,88 @@
#pragma once
#include <IPC/detail/Connect.h>
#include <IPC/Policies/TimeoutFactory.h>
#include <IPC/Policies/ErrorHandler.h>
#include "Client.h"
#include "Server.h"
#include <bond/core/bond_const_enum.h>
#include <memory>
#include <chrono>
namespace IPC
{
namespace Bond
{
template <
typename PacketConnector,
typename TimeoutFactory = typename PacketConnector::Traits::TimeoutFactory,
typename ErrorHandler = typename PacketConnector::Traits::ErrorHandler,
typename... TransactionArgs>
auto ConnectClient(
const char* acceptorName,
std::shared_ptr<PacketConnector> connector,
bool async,
bond::ProtocolType protocol = bond::ProtocolType::COMPACT_PROTOCOL,
bool marshal = true,
std::size_t minBlobSize = 0,
TimeoutFactory&& timeoutFactory = { std::chrono::seconds{ 1 } },
ErrorHandler&& errorHandler = {},
typename PacketConnector::Traits::TransactionManagerFactory transactionManagerFactory = {},
TransactionArgs&&... transactionArgs)
{
return IPC::detail::Connect(
acceptorName,
std::move(connector),
async,
std::forward<TimeoutFactory>(timeoutFactory),
std::forward<ErrorHandler>(errorHandler),
[protocol, marshal, minBlobSize, transactionManagerFactory = std::move(transactionManagerFactory)](auto&& connection, auto&& callback)
{
using Client = Client<typename PacketConnector::Request, typename PacketConnector::Response, typename PacketConnector::Traits>;
return MakeClient<typename PacketConnector::Request, typename PacketConnector::Response, typename PacketConnector::Traits>(
std::move(connection),
std::forward<decltype(callback)>(callback),
protocol,
marshal,
minBlobSize,
transactionManagerFactory(IPC::detail::Identity<typename Client::TransactionManager>{}));
},
std::forward<TransactionArgs>(transactionArgs)...);
}
template <
typename PacketConnector,
typename HandlerFactory,
typename TimeoutFactory = typename PacketConnector::Traits::TimeoutFactory,
typename ErrorHandler = typename PacketConnector::Traits::ErrorHandler,
typename... TransactionArgs>
auto ConnectServer(
const char* acceptorName,
std::shared_ptr<PacketConnector> connector,
HandlerFactory&& handlerFactory,
bool async,
bond::ProtocolType protocol = bond::ProtocolType::COMPACT_PROTOCOL,
bool marshal = true,
std::size_t minBlobSize = 0,
TimeoutFactory&& timeoutFactory = { std::chrono::seconds{ 1 } },
ErrorHandler&& errorHandler = {},
TransactionArgs&&... transactionArgs)
{
return IPC::detail::Connect(
acceptorName,
std::move(connector),
async,
std::forward<TimeoutFactory>(timeoutFactory),
std::forward<ErrorHandler>(errorHandler),
[protocol, marshal, minBlobSize, handlerFactory = std::forward<HandlerFactory>(handlerFactory)](auto&& connection, auto&& callback) mutable
{
return MakeServer<typename PacketConnector::Request, typename PacketConnector::Response, typename PacketConnector::Traits>(
std::move(connection), handlerFactory, std::forward<decltype(callback)>(callback), protocol, marshal, minBlobSize);
},
std::forward<TransactionArgs>(transactionArgs)...);
}
} // Bond
} // IPC

19
Inc/IPC/Bond/Connector.h Normal file
Просмотреть файл

@ -0,0 +1,19 @@
#pragma once
#include <IPC/Connector.h>
#include "detail/ComponentBase.h"
#include "DefaultTraits.h"
namespace IPC
{
namespace Bond
{
template <typename Request, typename Response, typename Traits = DefaultTraits>
using ClientConnector = detail::BufferComponent<ClientConnector, Request, Response, Traits>;
template <typename Request, typename Response, typename Traits = DefaultTraits>
using ServerConnector = detail::BufferComponent<ServerConnector, Request, Response, Traits>;
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,20 @@
#pragma once
#include <IPC/DefaultTraits.h>
#include "BufferPool.h"
#include "Serializer.h"
namespace IPC
{
namespace Bond
{
struct DefaultTraits : IPC::DefaultTraits
{
using BufferPool = DefaultBufferPool;
using Serializer = DefaultSerializer;
};
} // Bond
} // IPC

263
Inc/IPC/Bond/InputBuffer.h Normal file
Просмотреть файл

@ -0,0 +1,263 @@
#pragma once
#include "BlobCast.h"
#include "BufferPool.h"
#include <bond/core/traits.h>
#include <bond/stream/input_buffer.h>
#include <bond/protocol/encoding.h>
namespace IPC
{
namespace Bond
{
template <typename ConstBuffer>
class InputBuffer
{
public:
InputBuffer() = default;
InputBuffer(ConstBuffer buffer, std::shared_ptr<SharedMemory> memory)
: InputBuffer{ buffer ? InputBuffer{ std::move(memory), buffer, buffer.begin(), buffer.end() } : InputBuffer{} }
{}
InputBuffer(const typename ConstBuffer::Range& range, std::shared_ptr<SharedMemory> memory)
: InputBuffer{ std::move(memory), range.m_buffer, range.m_firstBlob, range.m_lastBlob, range.m_firstOffset, range.m_lastOffset }
{}
template <typename T>
void Read(T& value)
{
// Assuming primitives do not span over multiple blobs.
ReadSingle(sizeof(T), [&] { std::memcpy(&value, m_ptr, sizeof(T)); });
}
void Read(void* buffer, std::uint32_t size)
{
ReadMultiple(
size,
[&](std::size_t available)
{
std::memcpy(buffer, m_ptr, available);
buffer = static_cast<char*>(buffer) + available;
});
}
void Read(bond::blob& bondBlob, std::uint32_t size)
{
// Do not merge if spans over multiple blobs.
const auto& blob = *m_blob;
ReadSingle(size, [&] { bondBlob.assign(BlobCast(blob, m_memory), static_cast<std::uint32_t>(m_ptr - blob.data()), size); });
}
const void* Allocate(std::uint32_t size)
{
const void* ptr;
ReadSingle(size, [&] { ptr = m_ptr; });
return ptr;
}
template <typename T>
void ReadVariableUnsigned(T& value)
{
if (m_ptr + sizeof(T) * 8 / 7 < m_ptrEnd)
{
auto ptr = m_ptr;
bond::input_buffer::VariableUnsignedUnchecked<T, 0>::Read(ptr, value);
EndRead(ptr);
}
else
{
bond::GenericReadVariableUnsigned(*this, value);
}
}
void Skip(std::uint32_t size)
{
ReadMultiple(size, [](std::size_t) {});
}
bool IsEof() const
{
assert(m_isEof == (m_blob == m_blobEnd));
return m_isEof;
}
bool operator==(const InputBuffer& other) const
{
return m_ptr == other.m_ptr && m_blob == other.m_blob && m_blobEnd == other.m_blobEnd && m_lastOffset == other.m_lastOffset;
}
const std::shared_ptr<SharedMemory>& GetMemory() const
{
return m_memory;
}
private:
using BlobIterator = decltype(std::declval<ConstBuffer>().begin());
InputBuffer(
std::shared_ptr<SharedMemory> memory,
ConstBuffer buffer,
BlobIterator begin,
BlobIterator end,
std::size_t firstOffset = 0,
std::size_t lastOffset = 0)
: m_blob{ begin },
m_blobEnd{ lastOffset != 0 ? std::next(end) : end },
m_lastOffset{ lastOffset },
m_memory{ std::move(memory) },
m_buffer{ std::move(buffer) }
{
if (UpdateData())
{
m_ptr += firstOffset;
}
}
template <typename Function>
void ReadMultiple(std::size_t size, Function&& func)
{
auto ptr = m_ptr;
auto ptrEnd = m_ptrEnd;
auto blob = m_blob;
try
{
while (size != 0)
{
const auto n = std::min<std::size_t>(m_ptrEnd - m_ptr, size);
ReadSingle(n, [&] { func(n); });
size -= n;
}
}
catch (...)
{
m_ptr = ptr;
m_ptrEnd = ptrEnd;
m_blob = blob;
m_isEof = (m_blob == m_blobEnd);
throw;
}
}
void BeginRead(const char* ptr) const
{
if (ptr > m_ptrEnd || IsEof())
{
throw std::out_of_range{ "Out of buffer range." };
}
}
void EndRead(const char* ptr)
{
if (ptr != m_ptrEnd)
{
m_ptr = ptr;
}
else
{
MoveNext();
}
}
__declspec(noinline) void MoveNext()
{
m_isEof = (++m_blob == m_blobEnd);
UpdateData();
}
bool SkipEmptyBlobs()
{
for (; m_blob != m_blobEnd; ++m_blob)
{
const auto& blob = *m_blob;
if (blob && blob.size() != 0)
{
return false;
}
}
m_isEof = true;
return true;
}
template <typename Function>
void ReadSingle(std::size_t size, Function&& func)
{
const auto ptr = m_ptr + size;
BeginRead(ptr);
std::forward<Function>(func)();
EndRead(ptr);
}
bool UpdateData()
{
if (!SkipEmptyBlobs())
{
const auto& blob = *m_blob;
m_ptr = blob.data();
m_ptrEnd = blob.data() + (m_lastOffset != 0 && std::next(m_blob) == m_blobEnd ? m_lastOffset : blob.size());
return true;
}
m_ptr = m_ptrEnd = nullptr;
return false;
}
friend auto GetCurrentBuffer(const InputBuffer& buffer)
{
return buffer;
}
friend auto GetBufferRange(const InputBuffer& begin, const InputBuffer& end)
{
assert(begin.m_buffer == end.m_buffer);
assert(end.IsEof() || !begin.IsEof());
return typename ConstBuffer::Range{
begin.m_buffer,
begin.m_blob,
begin.IsEof() ? 0 : std::size_t(begin.m_ptr - begin.m_blob->data()),
end.m_blob,
end.IsEof() ? 0 : std::size_t(end.m_ptr - end.m_blob->data()) };
}
friend auto CreateInputBuffer(const InputBuffer& other, const typename ConstBuffer::Range& range)
{
return InputBuffer{ range, other.m_memory };
}
const char* m_ptr{ nullptr };
const char* m_ptrEnd{ nullptr };
BlobIterator m_blob{};
BlobIterator m_blobEnd{};
bool m_isEof{ m_blob == m_blobEnd };
std::size_t m_lastOffset{ 0 };
std::shared_ptr<SharedMemory> m_memory; // Must be declared before m_buffer.
ConstBuffer m_buffer{};
};
using DefaultInputBuffer = InputBuffer<DefaultBufferPool::ConstBuffer>;
} // Bond
} // IPC
namespace bond
{
BOND_DEFINE_BUFFER_MAGIC(IPC::Bond::DefaultInputBuffer, 0x5349 /*SB*/);
} // namespace bond

228
Inc/IPC/Bond/OutputBuffer.h Normal file
Просмотреть файл

@ -0,0 +1,228 @@
#pragma once
#include "BlobCast.h"
#include "BufferPool.h"
#include <bond/stream/output_buffer.h>
#include <bond/protocol/encoding.h>
namespace IPC
{
namespace Bond
{
template <typename BufferPool>
class OutputBuffer
{
public:
explicit OutputBuffer(std::shared_ptr<BufferPool> pool, std::size_t minBlobSize = 0)
: m_buffer{ pool->TakeBuffer() },
m_pool{ std::move(pool) },
m_minBlobSize{ minBlobSize != 0 ? minBlobSize : 4096 }
{
TakeBlob();
}
template <typename T>
void Write(const T& value)
{
if (m_ptr + sizeof(T) < m_ptrEnd)
{
std::memcpy(m_ptr, &value, sizeof(T));
m_ptr += sizeof(T);
}
else
{
Write(&value, sizeof(T));
}
}
void Write(const void* value, std::uint32_t size)
{
std::memcpy(Allocate(size), value, size);
}
void* Allocate(std::uint32_t size)
{
if (m_ptr + size >= m_ptrEnd)
{
auto& blob = *m_blob;
auto offset = m_ptr - blob.data();
blob.resize(offset + std::max<std::size_t>(size, m_minBlobSize), boost::container::default_init);
m_ptr = blob.data() + offset;
m_ptrEnd = blob.data() + blob.size();
}
auto ptr = m_ptr;
m_ptr += size;
return ptr;
}
void Write(const bond::blob& blob)
{
Write(BlobCast<typename BufferPool::ConstBlob>(blob), blob);
}
void Write(const typename BufferPool::ConstBuffer& buffer)
{
if (buffer)
{
for (const auto& blob : buffer)
{
Write(blob);
}
}
}
void Write(const typename BufferPool::ConstBuffer::Range& range)
{
if (!range.IsEmpty())
{
const auto& first = range.m_firstBlob;
auto length = std::distance(
first,
range.m_lastOffset != 0 ? std::next(range.m_lastBlob) : range.m_lastBlob);
assert(length != 0);
if (length == 1)
{
Write(first->GetRange(
range.m_firstOffset,
(range.m_lastOffset != 0 ? range.m_lastOffset : first->size()) - range.m_firstOffset));
}
else
{
auto last = std::next(first, length - 1);
Write(range.m_firstOffset != 0
? first->GetRange(range.m_firstOffset, first->size() - range.m_firstOffset)
: *first);
for (auto it = std::next(first); it != last; ++it)
{
Write(*it);
}
Write(range.m_lastOffset != 0
? last->GetRange(0, range.m_lastOffset)
: *last);
}
}
}
template<typename T>
void WriteVariableUnsigned(T value)
{
if (m_ptr + sizeof(T) * 8 / 7 < m_ptrEnd)
{
m_ptr += bond::output_buffer::VariableUnsignedUnchecked<T, 1>::Write(m_ptr, value);
}
else
{
bond::GenericWriteVariableUnsigned(*this, value);
}
}
void Flush()
{
if (Merge())
{
TakeBlob();
}
}
const typename BufferPool::Buffer& GetBuffer() const &
{
if (m_ptr != m_blob->data())
{
throw std::runtime_error{ "Buffer is not flushed." };
}
return m_buffer;
}
const typename BufferPool::Buffer& GetBuffer() &
{
Flush();
return m_buffer;
}
typename BufferPool::ConstBuffer GetBuffer() &&
{
Merge();
return std::move(m_buffer);
}
const std::shared_ptr<BufferPool>& GetBufferPool() const
{
return m_pool;
}
private:
void TakeBlob()
{
m_blob = m_pool->TakeBlob();
m_blob->resize(std::max<std::size_t>(m_blob->capacity(), m_minBlobSize), boost::container::default_init);
m_ptr = m_blob->data();
m_ptrEnd = m_blob->data() + m_blob->size();
}
bool Merge()
{
auto offset = m_ptr - m_blob->data();
if (offset != 0)
{
m_blob->resize(offset);
m_buffer->push_back(std::move(m_blob));
return true;
}
return false;
}
template <typename OtherBlob>
void Write(const typename BufferPool::ConstBlob& blob, const OtherBlob& otherBlob)
{
if (blob && m_pool->GetMemory()->Contains(blob.data()))
{
assert(m_pool->GetMemory()->Contains(blob.data() + blob.size() - 1));
Flush();
m_buffer->push_back(blob);
}
else
{
Write(otherBlob.data(), static_cast<uint32_t>(otherBlob.size()));
}
}
void Write(const typename BufferPool::ConstBlob& blob)
{
Write(blob, blob);
}
friend auto CreateOutputBuffer(const OutputBuffer& other)
{
return OutputBuffer{ other.m_pool };
}
char* m_ptr{ nullptr };
char* m_ptrEnd{ nullptr };
typename BufferPool::Blob m_blob;
typename BufferPool::Buffer m_buffer;
std::shared_ptr<BufferPool> m_pool;
std::size_t m_minBlobSize;
};
using DefaultOutputBuffer = OutputBuffer<DefaultBufferPool>;
} // Bond
} // IPC

157
Inc/IPC/Bond/Serializer.h Normal file
Просмотреть файл

@ -0,0 +1,157 @@
#pragma once
#include "OutputBuffer.h"
#include "InputBuffer.h"
#include "BufferPool.h"
#include <bond/core/bond.h>
#include <memory>
#include <future>
namespace IPC
{
namespace Bond
{
struct DefaultProtocols
: bond::Protocols<
bond::CompactBinaryReader<DefaultInputBuffer>,
bond::SimpleBinaryReader<DefaultInputBuffer>,
bond::FastBinaryReader<DefaultInputBuffer>,
bond::SimpleJsonReader<DefaultInputBuffer>> {};
template <template <typename> typename Writer, typename Protocols = DefaultProtocols, typename BufferPool, typename T>
typename BufferPool::ConstBuffer Serialize(std::shared_ptr<BufferPool> pool, const T& value, std::size_t minBlobSize = 0)
{
OutputBuffer<BufferPool> output{ std::move(pool), minBlobSize };
Writer<decltype(output)> writer{ output };
bond::Serialize<Protocols>(value, writer);
return std::move(output).GetBuffer();
}
template <typename Protocols = DefaultProtocols, typename BufferPool, typename T>
typename BufferPool::ConstBuffer Serialize(bond::ProtocolType protocol, std::shared_ptr<BufferPool> pool, const T& value, std::size_t minBlobSize = 0)
{
OutputBuffer<BufferPool> output{ std::move(pool), minBlobSize };
bond::Apply<bond::Serializer, Protocols>(value, output, static_cast<std::uint16_t>(protocol));
return std::move(output).GetBuffer();
}
template <template <typename> typename Reader, typename Protocols = DefaultProtocols, typename ConstBuffer, typename T>
void Deserialize(ConstBuffer&& buffer, T& value, std::shared_ptr<SharedMemory> memory)
{
InputBuffer<std::decay_t<ConstBuffer>> input{ std::forward<ConstBuffer>(buffer), std::move(memory) };
Reader<decltype(input)> reader{ std::move(input) };
bond::Deserialize<Protocols>(reader, value);
}
template <typename Protocols = DefaultProtocols, typename ConstBuffer, typename T>
void Deserialize(bond::ProtocolType protocol, ConstBuffer&& buffer, T& value, std::shared_ptr<SharedMemory> memory)
{
InputBuffer<std::decay_t<ConstBuffer>> input{ std::forward<ConstBuffer>(buffer), std::move(memory) };
bond::Apply<T, Protocols>(bond::To<T, Protocols>{ value }, input, static_cast<std::uint16_t>(protocol));
}
template <template <typename> typename Writer, typename Protocols = DefaultProtocols, typename BufferPool, typename T>
typename BufferPool::ConstBuffer Marshal(std::shared_ptr<BufferPool> pool, const T& value, std::size_t minBlobSize = 0)
{
OutputBuffer<BufferPool> output{ std::move(pool), minBlobSize };
Writer<decltype(output)> writer{ output };
bond::Marshal<Protocols>(value, writer);
return std::move(output).GetBuffer();
}
template <typename Protocols = DefaultProtocols, typename BufferPool, typename T>
typename BufferPool::ConstBuffer Marshal(bond::ProtocolType protocol, std::shared_ptr<BufferPool> pool, const T& value, std::size_t minBlobSize = 0)
{
OutputBuffer<BufferPool> output{ std::move(pool), minBlobSize };
bond::Apply<bond::Marshaler, Protocols>(value, output, static_cast<std::uint16_t>(protocol));
return std::move(output).GetBuffer();
}
template <typename Protocols = DefaultProtocols, typename ConstBuffer, typename T>
void Unmarshal(ConstBuffer&& buffer, T& value, std::shared_ptr<SharedMemory> memory)
{
bond::Unmarshal<Protocols>(InputBuffer<std::decay_t<ConstBuffer>>{ std::forward<ConstBuffer>(buffer), std::move(memory) }, value);
}
template <typename BufferPool, typename ProtocolsT = DefaultProtocols>
class Serializer // TODO: Add compile-time protocol support.
{
public:
using Protocols = ProtocolsT;
Serializer(bond::ProtocolType protocol, bool marshal, std::shared_ptr<BufferPool> outputPool, std::shared_ptr<SharedMemory> inputMemory, std::size_t minBlobSize = 0)
: m_outputPool{ std::move(outputPool) },
m_inputMemory{ std::move(inputMemory) },
m_protocol{ protocol },
m_marshal{ marshal },
m_minBlobSize{ minBlobSize }
{}
bond::ProtocolType GetProtocolType() const
{
return m_protocol;
}
bool IsMarshaled() const
{
return m_marshal;
}
template <typename T>
typename BufferPool::ConstBuffer Serialize(const T& value)
{
return m_marshal
? Bond::Marshal<Protocols>(m_protocol, m_outputPool, value, m_minBlobSize)
: Bond::Serialize<Protocols>(m_protocol, m_outputPool, value, m_minBlobSize);
}
template <typename T>
void Deserialize(typename BufferPool::ConstBuffer&& buffer, T& value)
{
m_marshal
? Bond::Unmarshal<Protocols>(std::move(buffer), value, m_inputMemory)
: Bond::Deserialize<Protocols>(m_protocol, std::move(buffer), value, m_inputMemory);
}
template <typename T>
std::future<T> Deserialize(typename BufferPool::ConstBuffer buffer)
{
std::packaged_task<T()> task{
[&]
{
T value;
Deserialize(std::move(buffer), value);
return value;
} };
task();
return task.get_future();
}
const std::shared_ptr<BufferPool>& GetOutputBufferPool() const
{
return m_outputPool;
}
const std::shared_ptr<SharedMemory>& GetInputMemory() const
{
return m_inputMemory;
}
private:
std::shared_ptr<BufferPool> m_outputPool;
std::shared_ptr<SharedMemory> m_inputMemory;
bond::ProtocolType m_protocol;
bool m_marshal;
std::size_t m_minBlobSize;
};
using DefaultSerializer = Serializer<DefaultBufferPool>;
} // Bond
} // IPC

58
Inc/IPC/Bond/Server.h Normal file
Просмотреть файл

@ -0,0 +1,58 @@
#pragma once
#include "detail/ComponentBase.h"
#include <IPC/Server.h>
#include "DefaultTraits.h"
#include <bond/core/bond_const_enum.h>
namespace IPC
{
namespace Bond
{
template <typename Request, typename Response, typename Traits = DefaultTraits>
class Server : public detail::ComponentBase<IPC::Server, Request, Response, Traits>
{
using Base = detail::ComponentBase<IPC::Server, Request, Response, Traits>;
public:
template <typename Handler, typename CloseHandler>
Server(typename Base::BufferPoolHolder pools, typename Base::Serializer serializer, std::unique_ptr<typename Base::Connection> connection, Handler&& handler, CloseHandler&& closeHandler)
: Base{
std::move(pools),
serializer,
std::move(connection),
[serializer, handler = std::forward<Handler>(handler)](typename Traits::BufferPool::ConstBuffer&& buffer, auto&& callback) mutable
{
handler(
serializer.template Deserialize<Request>(std::move(buffer)),
[serializer, callback = std::forward<decltype(callback)>(callback)](const Response& response) mutable
{
callback(serializer.Serialize(response));
});
},
std::forward<CloseHandler>(closeHandler) }
{}
};
template <typename Request, typename Response, typename Traits = DefaultTraits, typename HandlerFactory, typename CloseHandler>
auto MakeServer(
std::unique_ptr<typename Server<Request, Response, Traits>::Connection> connection,
HandlerFactory&& handlerFactory,
CloseHandler&& closeHandler,
bond::ProtocolType protocol = bond::ProtocolType::COMPACT_PROTOCOL,
bool marshal = true,
std::size_t minBlobSize = 0)
{
auto pools = detail::MakeBufferPoolHolder<typename Traits::BufferPool>(*connection);
typename Traits::Serializer serializer{ protocol, marshal, pools.GetOutputPool(), pools.GetInputPool()->GetMemory(), minBlobSize };
auto handler = handlerFactory(*connection, pools, serializer);
return std::make_unique<Server<Request, Response, Traits>>(
std::move(pools), std::move(serializer), std::move(connection), std::move(handler), std::forward<CloseHandler>(closeHandler));
}
} // Bond
} // IPC

200
Inc/IPC/Bond/Transport.h Normal file
Просмотреть файл

@ -0,0 +1,200 @@
#pragma once
#include "Acceptor.h"
#include "Accept.h"
#include "Connector.h"
#include "Connect.h"
#include <memory>
#include <mutex>
namespace IPC
{
namespace Bond
{
struct DefaultTraits;
template <typename Request, typename Response, typename Traits = DefaultTraits>
class Transport
{
public:
using Client = Client<Request, Response, Traits>;
using Server = Server<Request, Response, Traits>;
using ClientConnector = ClientConnector<Request, Response, Traits>;
using ServerConnector = ServerConnector<Request, Response, Traits>;
using ClientAcceptor = ClientAcceptor<Request, Response, Traits>;
using ServerAcceptor = ServerAcceptor<Request, Response, Traits>;
Transport()
: Transport{ bond::ProtocolType::COMPACT_PROTOCOL }
{}
explicit Transport(
bond::ProtocolType protocol,
bool marshal = true,
ChannelSettings<Traits> channelSettings = {},
std::size_t minBlobSize = 0,
std::size_t hostInfoMemorySize = 0,
typename Traits::TimeoutFactory timeoutFactory = {},
typename Traits::ErrorHandler errorHandler = {},
typename Traits::TransactionManagerFactory transactionManagerFactory = {})
: m_protocol{ protocol },
m_marshal{ marshal },
m_channelSettings{ std::move(channelSettings) },
m_minBlobSize{ minBlobSize },
m_hostInfoMemorySize{ hostInfoMemorySize },
m_timeoutFactory{ std::move(timeoutFactory) },
m_errorHandler{ std::move(errorHandler) },
m_transactionManagerFactory{ std::move(transactionManagerFactory) }
{}
template <typename CloseHandler>
auto MakeClient(std::unique_ptr<typename Client::Connection> connection, CloseHandler&& closeHandler)
{
return IPC::Bond::MakeClient<Request, Response, Traits>(
std::move(connection),
std::forward<CloseHandler>(closeHandler),
m_protocol,
m_marshal,
m_minBlobSize,
m_transactionManagerFactory(IPC::detail::Identity<typename Client::TransactionManager>{}));
}
template <typename HandlerFactory, typename CloseHandler>
auto MakeServer(std::unique_ptr<typename Server::Connection> connection, HandlerFactory&& handlerFactory, CloseHandler&& closeHandler)
{
return IPC::Bond::MakeServer<Request, Response, Traits>(
std::move(connection),
std::forward<HandlerFactory>(handlerFactory),
std::forward<CloseHandler>(closeHandler),
m_protocol,
m_marshal,
m_minBlobSize);
}
auto MakeClientConnector()
{
return ClientConnector{ m_channelSettings, m_transactionManagerFactory };
}
auto MakeServerConnector()
{
return ServerConnector{ m_channelSettings, m_transactionManagerFactory };
}
template <typename Handler>
auto MakeServerAcceptor(const char* name, Handler&& handler)
{
return ServerAcceptor{ name, std::forward<Handler>(handler), m_channelSettings, m_hostInfoMemorySize };
}
template <typename Handler>
auto MakeClientAcceptor(const char* name, Handler&& handler)
{
return ClientAcceptor{ name, std::forward<Handler>(handler), m_channelSettings, m_hostInfoMemorySize };
}
template <typename... TransactionArgs>
auto ConnectClient(
const char* name,
bool async,
std::shared_ptr<ClientConnector> connector = {},
TransactionArgs&&... transactionArgs)
{
if (!connector)
{
std::call_once(
m_clientConnectorOnceFlag,
[this] { m_clientConnector = std::make_shared<ClientConnector>(MakeClientConnector()); });
connector = m_clientConnector;
}
return IPC::Bond::ConnectClient(
name,
connector,
async,
m_protocol,
m_marshal,
m_minBlobSize,
m_timeoutFactory,
m_errorHandler,
m_transactionManagerFactory,
std::forward<TransactionArgs>(transactionArgs)...);
}
template <typename HandlerFactory, typename... TransactionArgs>
auto ConnectServer(
const char* name,
HandlerFactory&& handlerFactory,
bool async,
std::shared_ptr<ServerConnector> connector = {},
TransactionArgs&&... transactionArgs)
{
if (!connector)
{
std::call_once(
m_serverConnectorOnceFlag,
[this] { m_serverConnector = std::make_shared<ServerConnector>(MakeServerConnector()); });
connector = m_serverConnector;
}
return IPC::Bond::ConnectServer(
name,
connector,
std::forward<HandlerFactory>(handlerFactory),
async,
m_protocol,
m_marshal,
m_minBlobSize,
m_timeoutFactory,
m_errorHandler,
std::forward<TransactionArgs>(transactionArgs)...);
}
template <typename HandlerFactory>
auto AcceptServers(const char* name, HandlerFactory&& handlerFactory)
{
return IPC::Bond::AcceptServers<Request, Response, Traits>(
name,
std::forward<HandlerFactory>(handlerFactory),
m_protocol,
m_marshal,
m_channelSettings,
m_minBlobSize,
m_hostInfoMemorySize,
m_errorHandler);
}
auto AcceptClients(const char* name)
{
return IPC::Bond::AcceptClients<Request, Response, Traits>(
name,
m_protocol,
m_marshal,
m_channelSettings,
m_minBlobSize,
m_hostInfoMemorySize,
m_errorHandler,
m_transactionManagerFactory);
}
private:
bond::ProtocolType m_protocol;
bool m_marshal;
ChannelSettings<Traits> m_channelSettings;
std::size_t m_minBlobSize;
std::size_t m_hostInfoMemorySize;
typename Traits::TimeoutFactory m_timeoutFactory;
typename Traits::ErrorHandler m_errorHandler;
typename Traits::TransactionManagerFactory m_transactionManagerFactory;
std::shared_ptr<ClientConnector> m_clientConnector;
std::shared_ptr<ServerConnector> m_serverConnector;
std::once_flag m_clientConnectorOnceFlag;
std::once_flag m_serverConnectorOnceFlag;
};
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,57 @@
#pragma once
#include <bond/core/blob.h>
#include <cassert>
namespace IPC
{
class SharedMemory;
namespace Bond
{
namespace detail
{
template <typename Blob>
struct BlobHolder
{
explicit BlobHolder(Blob blob, std::shared_ptr<SharedMemory> memory = {})
: m_memory{ std::move(memory) },
m_blob{ std::move(blob) }
{}
void operator()(const char* buffer)
{
if (buffer != nullptr)
{
assert(m_blob);
assert(buffer == m_blob.data());
m_blob = {};
}
}
std::shared_ptr<SharedMemory> m_memory; // Must be declared before m_blob.
Blob m_blob;
};
struct BlobHook : boost::shared_ptr<const char[]>
{
using shared_ptr::shared_ptr;
};
} // detail
} // Bond
} // IPC
namespace bond
{
template <>
inline IPC::Bond::detail::BlobHook blob_cast(const blob& from)
{
return from._buffer;
}
} // bond

Просмотреть файл

@ -0,0 +1,55 @@
#pragma once
#include <memory>
namespace IPC
{
namespace Bond
{
namespace detail
{
template <typename BufferPool>
class BufferPoolHolder
{
public:
BufferPoolHolder(std::shared_ptr<BufferPool> inPool, std::shared_ptr<BufferPool> outPool)
: m_inPool{ std::move(inPool) },
m_outPool{ std::move(outPool) }
{}
const std::shared_ptr<BufferPool>& GetInputPool() const
{
return m_inPool;
}
const std::shared_ptr<BufferPool>& GetOutputPool() const
{
return m_outPool;
}
private:
std::shared_ptr<BufferPool> m_inPool;
std::shared_ptr<BufferPool> m_outPool;
};
template <typename BufferPool, typename Connection>
auto MakeBufferPoolHolder(const Connection& connection)
{
auto pools = std::make_shared<std::pair<BufferPool, BufferPool>>(
std::piecewise_construct,
std::forward_as_tuple(connection.GetInputChannel().GetMemory()),
std::forward_as_tuple(connection.GetOutputChannel().GetMemory()));
auto& pair = *pools;
std::shared_ptr<BufferPool> in{ pools, &pair.first };
std::shared_ptr<BufferPool> out{ std::move(pools), &pair.second };
return BufferPoolHolder<BufferPool>{ std::move(in), std::move(out) };
}
} // detail
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,61 @@
#pragma once
#include "BufferPoolHolder.h"
#include "BufferPoolFwd.h"
#include <type_traits>
namespace IPC
{
namespace Bond
{
namespace detail
{
template <template <typename, typename, typename> typename Component, typename Request, typename Response, typename Traits>
using BufferComponentOf = Component<
ConstBuffer<typename Traits::BufferPool>,
std::conditional_t<std::is_void<Response>::value, void, ConstBuffer<typename Traits::BufferPool>>,
Traits>;
template <template <typename, typename, typename> typename Component, typename RequestT, typename ResponseT, typename TraitsT>
class BufferComponent : public BufferComponentOf<Component, RequestT, ResponseT, TraitsT>
{
using Base = BufferComponentOf<Component, RequestT, ResponseT, TraitsT>;
public:
using Request = RequestT;
using Response = ResponseT;
using Traits = TraitsT;
template <typename... Args>
BufferComponent(Args&&... args) // TODO: Inherit constructors instead when VC14 bugs are fixed.
: Base{ std::forward<Args>(args)... }
{}
};
template <template <typename, typename, typename> typename Component, typename Request, typename Response, typename Traits>
class ComponentBase
: public BufferComponent<Component, Request, Response, Traits>,
public BufferPoolHolder<typename Traits::BufferPool>,
public Traits::Serializer
{
using BufferComponent = BufferComponent<Component, Request, Response, Traits>;
protected:
using BufferPoolHolder = BufferPoolHolder<typename Traits::BufferPool>;
using Serializer = typename Traits::Serializer;
public:
template <typename... Args>
ComponentBase(BufferPoolHolder pools, Serializer serializer, Args&&... args)
: BufferComponent{ std::forward<Args>(args)... },
BufferPoolHolder{ std::move(pools) },
Serializer{ std::move(serializer) }
{}
};
} // detail
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Inc\detail\Interop\BufferPool.h" />
<ClInclude Include="..\Inc\detail\Interop\InputBuffer.h" />
<ClInclude Include="..\Inc\detail\Interop\OutputBuffer.h" />
<ClInclude Include="..\Inc\stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Src\detail\Interop\BufferPool.cpp" />
<ClCompile Include="..\Src\detail\Interop\InputBuffer.cpp" />
<ClCompile Include="..\Src\detail\Interop\OutputBuffer.cpp" />
<ClCompile Include="..\Src\detail\Interop\Transport.cpp" />
<ClCompile Include="..\Src\stdafx.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A13012C1-76DE-4D1D-A58B-2361D2BE8F65}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<TargetName>IPC.Bond.Interop</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<Lib>
<TargetMachine>MachineX64</TargetMachine>
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\..\Inc;..\Inc;..\..\IPC\Inc;..\..\bond\build\target\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;4503;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Speed</FavorSizeOrSpeed>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets" Condition="Exists('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" />
<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('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="detail">
<UniqueIdentifier>{45e3f9ed-bd76-4f45-8e40-1d9c56304c65}</UniqueIdentifier>
</Filter>
<Filter Include="detail\Interop">
<UniqueIdentifier>{647cf641-c404-49b8-ae45-ca5de6ea9686}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Src\stdafx.cpp">
<Filter>detail</Filter>
</ClCompile>
<ClCompile Include="..\Src\detail\Interop\BufferPool.cpp">
<Filter>detail\Interop</Filter>
</ClCompile>
<ClCompile Include="..\Src\detail\Interop\InputBuffer.cpp">
<Filter>detail\Interop</Filter>
</ClCompile>
<ClCompile Include="..\Src\detail\Interop\OutputBuffer.cpp">
<Filter>detail\Interop</Filter>
</ClCompile>
<ClCompile Include="..\Src\detail\Interop\Transport.cpp">
<Filter>detail\Interop</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Inc\stdafx.h">
<Filter>detail</Filter>
</ClInclude>
<ClInclude Include="..\Inc\detail\Interop\BufferPool.h">
<Filter>detail\Interop</Filter>
</ClInclude>
<ClInclude Include="..\Inc\detail\Interop\InputBuffer.h">
<Filter>detail\Interop</Filter>
</ClInclude>
<ClInclude Include="..\Inc\detail\Interop\OutputBuffer.h">
<Filter>detail\Interop</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.63.0.0" targetFramework="native" />
</packages>

Просмотреть файл

@ -0,0 +1,48 @@
#pragma once
#pragma managed(push, off)
#include <IPC/Managed/detail/Interop/SharedMemory.h>
#include <IPC/Bond/BufferPoolFwd.h>
#include <memory>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
namespace Interop
{
class BufferPool : public std::shared_ptr<IPC::Bond::DefaultBufferPool>
{
public:
class ConstBuffer : public std::shared_ptr<IPC::Bond::DefaultConstBuffer>
{
public:
ConstBuffer(const IPC::Bond::DefaultConstBuffer& impl);
~ConstBuffer();
std::size_t GetSize() const;
std::size_t CopyTo(void* buffer, std::size_t size) const;
};
explicit BufferPool(const std::shared_ptr<IPC::SharedMemory>& memory);
~BufferPool();
const std::shared_ptr<IPC::SharedMemory>& GetMemory() const;
};
} // Interop
} // detail
} // Managed
} // Bond
} // IPC
#pragma managed(pop)

Просмотреть файл

@ -0,0 +1,66 @@
#pragma once
#pragma managed(push, off)
#include "BufferPool.h"
#include <memory>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
namespace Interop
{
class InputBuffer
{
public:
InputBuffer();
InputBuffer(const BufferPool::ConstBuffer& buffer, const std::shared_ptr<IPC::SharedMemory>& memory);
InputBuffer(const InputBuffer& other);
~InputBuffer();
void Read(void* buffer, std::uint32_t size);
const void* Allocate(std::uint32_t size);
float ReadFloat();
double ReadDouble();
std::uint8_t ReadByte();
std::uint16_t ReadUInt16();
std::uint32_t ReadUInt32();
std::uint64_t ReadUInt64();
std::uint16_t ReadVarUInt16();
std::uint32_t ReadVarUInt32();
std::uint64_t ReadVarUInt64();
void Skip(std::uint32_t size);
private:
class Impl;
std::unique_ptr<Impl> m_impl;
};
} // Interop
} // detail
} // Managed
} // Bond
} // IPC
#pragma managed(pop)

Просмотреть файл

@ -0,0 +1,62 @@
#pragma once
#pragma managed(push, off)
#include "BufferPool.h"
#include <memory>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
namespace Interop
{
class OutputBuffer
{
public:
OutputBuffer(const BufferPool& pool, std::size_t minBlobSize);
~OutputBuffer();
void Write(const void* value, std::uint32_t size);
void* Allocate(std::uint32_t size);
void WriteFloat(float value);
void WriteDouble(double value);
void WriteByte(std::uint8_t value);
void WriteUInt16(std::uint16_t value);
void WriteUInt32(std::uint32_t value);
void WriteUInt64(std::uint64_t value);
void WriteVarUInt16(std::uint16_t value);
void WriteVarUInt32(std::uint32_t value);
void WriteVarUInt64(std::uint64_t value);
BufferPool::ConstBuffer GetBuffer() &&;
private:
class Impl;
std::unique_ptr<Impl> m_impl;
};
} // Interop
} // detail
} // Managed
} // Bond
} // IPC
#pragma managed(pop)

3
Interop/Inc/stdafx.h Normal file
Просмотреть файл

@ -0,0 +1,3 @@
#pragma once
#include <Windows.h>

Просмотреть файл

@ -0,0 +1,72 @@
#include "stdafx.h"
#include "detail/Interop/BufferPool.h"
#include <IPC/Bond/BufferPool.h>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
namespace Interop
{
BufferPool::ConstBuffer::ConstBuffer(const IPC::Bond::DefaultConstBuffer& impl)
: shared_ptr{ std::make_shared<IPC::Bond::DefaultConstBuffer>(impl) }
{}
BufferPool::ConstBuffer::~ConstBuffer() = default;
std::size_t BufferPool::ConstBuffer::GetSize() const
{
std::size_t size = 0;
for (const auto& blob : **this)
{
size += blob.size();
}
return size;
}
std::size_t BufferPool::ConstBuffer::CopyTo(void* buffer, std::size_t size) const
{
auto ptr = static_cast<char*>(buffer);
for (const auto& blob : **this)
{
if (auto sz = (std::min)(size, blob.size()))
{
std::memcpy(ptr, blob.data(), sz);
ptr += sz;
size -= sz;
}
else
{
break;
}
}
return ptr - static_cast<char*>(buffer);
}
BufferPool::BufferPool(const std::shared_ptr<IPC::SharedMemory>& memory)
: shared_ptr{ std::make_shared<IPC::Bond::DefaultBufferPool>(memory) }
{}
BufferPool::~BufferPool() = default;
const std::shared_ptr<IPC::SharedMemory>& BufferPool::GetMemory() const
{
return get()->GetMemory();
}
} // Interop
} // detail
} // Managed
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,122 @@
#include "stdafx.h"
#include "detail/Interop/InputBuffer.h"
#include <IPC/Bond/InputBuffer.h>
#include <IPC/Managed/detail/Throw.h>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
using IPC::Managed::detail::InvokeThrow;
namespace Interop
{
class InputBuffer::Impl : public IPC::Bond::DefaultInputBuffer
{
public:
using DefaultInputBuffer::DefaultInputBuffer;
};
InputBuffer::InputBuffer()
: m_impl{ std::make_unique<Impl>() }
{}
InputBuffer::InputBuffer(const BufferPool::ConstBuffer& buffer, const std::shared_ptr<IPC::SharedMemory>& memory)
: m_impl{ std::make_unique<Impl>(*buffer, memory) }
{}
InputBuffer::InputBuffer(const InputBuffer& other)
: m_impl{ std::make_unique<Impl>(*other.m_impl) }
{}
InputBuffer::~InputBuffer() = default;
void InputBuffer::Read(void* buffer, std::uint32_t size)
{
InvokeThrow([&] { m_impl->Read(buffer, size); });
}
const void* InputBuffer::Allocate(std::uint32_t size)
{
return InvokeThrow([&] { return m_impl->Allocate(size); });
}
float InputBuffer::ReadFloat()
{
float value;
InvokeThrow([&] { m_impl->Read(value); });
return value;
}
double InputBuffer::ReadDouble()
{
double value;
InvokeThrow([&] { m_impl->Read(value); });
return value;
}
std::uint8_t InputBuffer::ReadByte()
{
std::uint8_t value;
InvokeThrow([&] { m_impl->Read(value); });
return value;
}
std::uint16_t InputBuffer::ReadUInt16()
{
std::uint16_t value;
InvokeThrow([&] { m_impl->Read(value); });
return value;
}
std::uint32_t InputBuffer::ReadUInt32()
{
std::uint32_t value;
InvokeThrow([&] { m_impl->Read(value); });
return value;
}
std::uint64_t InputBuffer::ReadUInt64()
{
std::uint64_t value;
InvokeThrow([&] { m_impl->Read(value); });
return value;
}
std::uint16_t InputBuffer::ReadVarUInt16()
{
std::uint16_t value;
InvokeThrow([&] { m_impl->ReadVariableUnsigned(value); });
return value;
}
std::uint32_t InputBuffer::ReadVarUInt32()
{
std::uint32_t value;
InvokeThrow([&] { m_impl->ReadVariableUnsigned(value); });
return value;
}
std::uint64_t InputBuffer::ReadVarUInt64()
{
std::uint64_t value;
InvokeThrow([&] { m_impl->ReadVariableUnsigned(value); });
return value;
}
void InputBuffer::Skip(std::uint32_t size)
{
InvokeThrow([&] { m_impl->Skip(size); });
}
} // Interop
} // detail
} // Managed
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,96 @@
#include "stdafx.h"
#include "detail/Interop/OutputBuffer.h"
#include <IPC/Bond/OutputBuffer.h>
#include <IPC/Managed/detail/Throw.h>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
using IPC::Managed::detail::InvokeThrow;
namespace Interop
{
class OutputBuffer::Impl : public IPC::Bond::DefaultOutputBuffer
{
public:
using DefaultOutputBuffer::DefaultOutputBuffer;
};
OutputBuffer::OutputBuffer(const BufferPool& pool, std::size_t minBlobSize)
: m_impl{ std::make_unique<Impl>(pool, minBlobSize) }
{}
OutputBuffer::~OutputBuffer() = default;
void OutputBuffer::Write(const void* value, std::uint32_t size)
{
InvokeThrow([&] { m_impl->Write(value, size); });
}
void* OutputBuffer::Allocate(std::uint32_t size)
{
return InvokeThrow([&] { return m_impl->Allocate(size); });
}
void OutputBuffer::WriteFloat(float value)
{
InvokeThrow([&] { m_impl->Write(value); });
}
void OutputBuffer::WriteDouble(double value)
{
InvokeThrow([&] { m_impl->Write(value); });
}
void OutputBuffer::WriteByte(std::uint8_t value)
{
InvokeThrow([&] { m_impl->Write(value); });
}
void OutputBuffer::WriteUInt16(std::uint16_t value)
{
InvokeThrow([&] { m_impl->Write(value); });
}
void OutputBuffer::WriteUInt32(std::uint32_t value)
{
InvokeThrow([&] { m_impl->Write(value); });
}
void OutputBuffer::WriteUInt64(std::uint64_t value)
{
InvokeThrow([&] { m_impl->Write(value); });
}
void OutputBuffer::WriteVarUInt16(std::uint16_t value)
{
InvokeThrow([&] { m_impl->WriteVariableUnsigned(value); });
}
void OutputBuffer::WriteVarUInt32(std::uint32_t value)
{
InvokeThrow([&] { m_impl->WriteVariableUnsigned(value); });
}
void OutputBuffer::WriteVarUInt64(std::uint64_t value)
{
InvokeThrow([&] { m_impl->WriteVariableUnsigned(value); });
}
BufferPool::ConstBuffer OutputBuffer::GetBuffer() &&
{
return InvokeThrow([&] { return std::move(*m_impl).GetBuffer(); });
}
} // Interop
} // detail
} // Managed
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,20 @@
#include "stdafx.h"
#include "IPC/Managed/detail/Interop/TransportImpl.h"
#include <IPC/Bond/BufferPool.h>
namespace IPC
{
namespace Managed
{
namespace detail
{
namespace Interop
{
template Transport<IPC::Bond::DefaultConstBuffer, IPC::Bond::DefaultConstBuffer>;
} // Interop
} // detail
} // Managed
} // IPC

1
Interop/Src/stdafx.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "stdafx.h"

10
LICENSE
Просмотреть файл

@ -1,6 +1,10 @@
MIT License
IPC.Bond (Inter-Process Communication via Bond)
Copyright (c) Microsoft Corporation. All rights reserved.
Copyright (c) Microsoft Corporation
All rights reserved. 
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -12,7 +16,7 @@
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

Просмотреть файл

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<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">
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<ProjectGuid>{705098F7-93DC-4954-8165-FDDCD66231F0}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CLRSupport>true</CLRSupport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<TargetName>IPC.Bond.$(ProjectName)</TargetName>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\IPC.Bond.snk</AssemblyOriginatorKeyFile>
<LinkKeyFile>..\..\IPC.Bond.snk</LinkKeyFile>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>wininet.lib;..\..\IPC\$(Platform)\$(Configuration)\IPC.lib;..\..\IPC\$(Platform)\$(Configuration)\IPC.Interop.lib;..\..\IPC\$(Platform)\$(Configuration)\IPC.Managed.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalOptions>/ignore:4248 %(AdditionalOptions)</AdditionalOptions>
</Link>
<Lib>
<TargetMachine>MachineX64</TargetMachine>
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\Inc;..\..\Inc;..\..\Interop\Inc;..\..\IPC\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="Bond">
<HintPath>..\..\IPC\Packages\Bond.Core.CSharp.6.0.0\lib\net45\Bond.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed">
<HintPath>..\..\IPC\$(Platform)\$(Configuration)\IPC.Managed.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed.Object">
<HintPath>..\..\IPC\$(Platform)\$(Configuration)\IPC.Managed.Object.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed.Transport">
<HintPath>..\..\IPC\$(Platform)\$(Configuration)\IPC.Managed.Transport.dll</HintPath>
</Reference>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Src\AssemblyInfo.cpp" />
<ClCompile Include="..\Src\BufferPool.cpp" />
<ClCompile Include="..\Src\InputStream.cpp" />
<ClCompile Include="..\Src\OutputStream.cpp" />
<ClCompile Include="..\Src\Transport.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Interop\Build\Interop.vcxproj">
<Project>{a13012c1-76de-4d1d-a58b-2361d2be8f65}</Project>
</ProjectReference>
<ProjectReference Include="..\..\Native\Build\Native.vcxproj">
<Project>{2030ED0D-4667-4299-87CD-ACE298BDF56D}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Inc\BufferPool.h" />
<ClInclude Include="..\Inc\InputStream.h" />
<ClInclude Include="..\Inc\OutputStream.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets" Condition="Exists('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" />
<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('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets'))" />
<Error Condition="!Exists('..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets'))" />
</Target>
<Import Project="..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets" Condition="Exists('..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets')" />
</Project>

Просмотреть файл

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\Src\AssemblyInfo.cpp" />
<ClCompile Include="..\Src\BufferPool.cpp" />
<ClCompile Include="..\Src\InputStream.cpp" />
<ClCompile Include="..\Src\OutputStream.cpp" />
<ClCompile Include="..\Src\Transport.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Inc\BufferPool.h" />
<ClInclude Include="..\Inc\InputStream.h" />
<ClInclude Include="..\Inc\OutputStream.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.63.0.0" targetFramework="native" />
<package id="boost_date_time-vc140" version="1.63.0.0" targetFramework="native" />
</packages>

60
Managed/Inc/BufferPool.h Normal file
Просмотреть файл

@ -0,0 +1,60 @@
#pragma once
#include "detail/Interop/BufferPool.h"
#include "IPC/Managed/detail/NativeObject.h"
namespace IPC
{
namespace Bond
{
namespace Managed
{
public ref class BufferPool
{
public:
ref class ConstBuffer
{
internal:
ConstBuffer(const detail::Interop::BufferPool::ConstBuffer& buffer);
property const detail::Interop::BufferPool::ConstBuffer& Impl
{
const detail::Interop::BufferPool::ConstBuffer& get();
}
public:
property System::Int32 Length
{
System::Int32 get();
}
void CopyTo(cli::array<System::Byte>^ buffer, System::Int32 offset);
private:
System::Int32 CalculateLength();
IPC::Managed::detail::NativeObject<detail::Interop::BufferPool::ConstBuffer> m_impl;
System::Lazy<System::Int32> m_length;
};
BufferPool(IPC::Managed::SharedMemory^ memory);
property IPC::Managed::SharedMemory^ Memory
{
IPC::Managed::SharedMemory^ get();
}
internal:
property detail::Interop::BufferPool& Impl
{
detail::Interop::BufferPool& get();
}
private:
IPC::Managed::detail::NativeObject<detail::Interop::BufferPool> m_impl;
};
} // Managed
} // Bond
} // IPC

65
Managed/Inc/InputStream.h Normal file
Просмотреть файл

@ -0,0 +1,65 @@
#pragma once
#include "BufferPool.h"
#include "detail/Interop/InputBuffer.h"
#include "IPC/Managed/detail/NativeObject.h"
namespace IPC
{
namespace Bond
{
namespace Managed
{
public ref class InputStream : public ::Bond::IO::IInputStream, public ::Bond::IO::ICloneable<InputStream^>
{
public:
InputStream(BufferPool::ConstBuffer^ buffer, IPC::Managed::SharedMemory^ inputMemory);
virtual property System::Int64 Length
{
System::Int64 get();
}
virtual property System::Int64 Position
{
System::Int64 get();
void set(System::Int64 value);
}
virtual System::Single ReadFloat();
virtual System::Double ReadDouble();
virtual System::Byte ReadUInt8();
virtual System::UInt16 ReadUInt16();
virtual System::UInt32 ReadUInt32();
virtual System::UInt64 ReadUInt64();
virtual System::UInt16 ReadVarUInt16();
virtual System::UInt32 ReadVarUInt32();
virtual System::UInt64 ReadVarUInt64();
virtual System::String^ ReadString(System::Text::Encoding^ encoding, System::Int32 count);
virtual System::ArraySegment<System::Byte> ReadBytes(System::Int32 count);
virtual void SkipBytes(System::Int32 count);
virtual InputStream^ Clone();
private:
InputStream(InputStream% other);
IPC::Managed::detail::NativeObject<detail::Interop::InputBuffer> m_impl;
};
} // Managed
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,56 @@
#pragma once
#include "BufferPool.h"
#include "detail/Interop/OutputBuffer.h"
#include "IPC/Managed/detail/NativeObject.h"
namespace IPC
{
namespace Bond
{
namespace Managed
{
public ref class OutputStream : ::Bond::IO::IOutputStream
{
public:
OutputStream(BufferPool^ pool, [System::Runtime::InteropServices::Optional] System::UInt32 minBlobSize);
virtual property System::Int64 Position
{
System::Int64 get();
void set(System::Int64 value);
}
virtual void WriteFloat(System::Single value);
virtual void WriteDouble(System::Double value);
virtual void WriteUInt8(System::Byte value);
virtual void WriteUInt16(System::UInt16 value);
virtual void WriteUInt32(System::UInt32 value);
virtual void WriteUInt64(System::UInt64 value);
virtual void WriteVarUInt16(System::UInt16 value);
virtual void WriteVarUInt32(System::UInt32 value);
virtual void WriteVarUInt64(System::UInt64 value);
virtual void WriteString(System::Text::Encoding^ encoding, System::String^ value, System::Int32 count);
virtual void WriteBytes(System::ArraySegment<System::Byte> data);
BufferPool::ConstBuffer^ GetBuffer();
private:
IPC::Managed::detail::NativeObject<detail::Interop::OutputBuffer> m_impl;
};
} // Managed
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,18 @@
using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::InteropServices;
[assembly:AssemblyTitleAttribute("IPC.Bond.Managed")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyCompanyAttribute("Microsoft")];
[assembly:AssemblyProductAttribute("IPC.Bond.Managed")];
[assembly:AssemblyCopyrightAttribute("Copyright © Microsoft 2017")];
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
[assembly:CLSCompliantAttribute(true)];
[assembly:ComVisible(false)];
[assembly:AssemblyVersionAttribute("1.0.*")];

Просмотреть файл

@ -0,0 +1,69 @@
#include "BufferPool.h"
namespace IPC
{
namespace Bond
{
namespace Managed
{
BufferPool::ConstBuffer::ConstBuffer(const detail::Interop::BufferPool::ConstBuffer& buffer)
: m_impl{ buffer },
m_length{
gcnew System::Func<System::Int32>(this, &BufferPool::ConstBuffer::CalculateLength),
System::Threading::LazyThreadSafetyMode::PublicationOnly }
{}
const detail::Interop::BufferPool::ConstBuffer& BufferPool::ConstBuffer::Impl::get()
{
return *m_impl;
}
System::Int32 BufferPool::ConstBuffer::CalculateLength()
{
return static_cast<int>(m_impl->GetSize());
}
System::Int32 BufferPool::ConstBuffer::Length::get()
{
return m_length.Value;
}
void BufferPool::ConstBuffer::CopyTo(cli::array<System::Byte>^ buffer, System::Int32 offset)
{
if (buffer == nullptr)
{
throw gcnew System::ArgumentNullException{ "buffer" };
}
auto length = Length;
if (length > 0)
{
if (offset + length > buffer->Length)
{
throw gcnew System::ArgumentException{ "Insufficient buffer size.", "buffer" };
}
pin_ptr<System::Byte> ptr = &buffer[offset];
m_impl->CopyTo(ptr, length);
}
}
BufferPool::BufferPool(IPC::Managed::SharedMemory^ memory)
: m_impl{ memory->Impl }
{}
IPC::Managed::SharedMemory^ BufferPool::Memory::get()
{
return gcnew IPC::Managed::SharedMemory{ m_impl->GetMemory() };
}
detail::Interop::BufferPool& BufferPool::Impl::get()
{
return *m_impl;
}
} // Managed
} // Bond
} // IPC

132
Managed/Src/InputStream.cpp Normal file
Просмотреть файл

@ -0,0 +1,132 @@
#include "InputStream.h"
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
using IPC::Managed::detail::ThrowManagedException;
} // detail
namespace
{
[[noreturn]] void ThrowNotImplemented()
{
throw gcnew System::NotImplementedException{};
}
} // anonymous
InputStream::InputStream(BufferPool::ConstBuffer^ buffer, IPC::Managed::SharedMemory^ inputMemory)
try
: m_impl{ buffer->Impl, inputMemory->Impl }
{}
catch (const std::exception& /*e*/)
{
detail::ThrowManagedException(std::current_exception());
}
InputStream::InputStream(InputStream% other)
try
: m_impl{ *other.m_impl }
{}
catch (const std::exception& /*e*/)
{
detail::ThrowManagedException(std::current_exception());
}
System::Int64 InputStream::Length::get()
{
ThrowNotImplemented();
}
System::Int64 InputStream::Position::get()
{
// TODO: Needs to be implemented. (?)
ThrowNotImplemented();
}
void InputStream::Position::set(System::Int64 value)
{
// TODO: Needs to be implemented. (?)
ThrowNotImplemented();
}
System::Single InputStream::ReadFloat()
{
return m_impl->ReadFloat();
}
System::Double InputStream::ReadDouble()
{
return m_impl->ReadDouble();
}
System::Byte InputStream::ReadUInt8()
{
return m_impl->ReadByte();
}
System::UInt16 InputStream::ReadUInt16()
{
return m_impl->ReadUInt16();
}
System::UInt32 InputStream::ReadUInt32()
{
return m_impl->ReadUInt32();
}
System::UInt64 InputStream::ReadUInt64()
{
return m_impl->ReadUInt64();
}
System::UInt16 InputStream::ReadVarUInt16()
{
return m_impl->ReadVarUInt16();
}
System::UInt32 InputStream::ReadVarUInt32()
{
return m_impl->ReadVarUInt32();
}
System::UInt64 InputStream::ReadVarUInt64()
{
return m_impl->ReadVarUInt64();
}
System::String^ InputStream::ReadString(System::Text::Encoding^ encoding, System::Int32 count)
{
auto ptr = m_impl->Allocate(count);
return encoding->GetString(static_cast<unsigned char*>(const_cast<void*>(ptr)), count);
}
System::ArraySegment<System::Byte> InputStream::ReadBytes(System::Int32 count)
{
auto buffer = gcnew cli::array<System::Byte>(count);
pin_ptr<System::Byte> ptr = &buffer[0];
m_impl->Read(ptr, count);
return System::ArraySegment<System::Byte>(buffer);
}
void InputStream::SkipBytes(System::Int32 count)
{
m_impl->Skip(count);
}
InputStream^ InputStream::Clone()
{
return gcnew InputStream{ *this };
}
} // Managed
} // Bond
} // IPC

Просмотреть файл

@ -0,0 +1,120 @@
#include "OutputStream.h"
#include <vcclr.h>
namespace IPC
{
namespace Bond
{
namespace Managed
{
namespace detail
{
using IPC::Managed::detail::ThrowManagedException;
} // detail
namespace
{
[[noreturn]] void ThrowNotImplemented()
{
throw gcnew System::NotImplementedException{};
}
} // anonymous
OutputStream::OutputStream(BufferPool^ pool, System::UInt32 minBlobSize)
try
: m_impl{ pool->Impl, static_cast<std::size_t>(minBlobSize) }
{}
catch (const std::exception& /*e*/)
{
detail::ThrowManagedException(std::current_exception());
}
System::Int64 OutputStream::Position::get()
{
#ifdef NDEBUG
ThrowNotImplemented();
#else
return 0;
#endif // NDEBUG
}
void OutputStream::Position::set(System::Int64 /*value*/)
{
ThrowNotImplemented();
}
void OutputStream::WriteFloat(System::Single value)
{
m_impl->WriteFloat(value);
}
void OutputStream::WriteDouble(System::Double value)
{
m_impl->WriteDouble(value);
}
void OutputStream::WriteUInt8(System::Byte value)
{
m_impl->WriteByte(value);
}
void OutputStream::WriteUInt16(System::UInt16 value)
{
m_impl->WriteUInt16(value);
}
void OutputStream::WriteUInt32(System::UInt32 value)
{
m_impl->WriteUInt32(value);
}
void OutputStream::WriteUInt64(System::UInt64 value)
{
m_impl->WriteUInt64(value);
}
void OutputStream::WriteVarUInt16(System::UInt16 value)
{
m_impl->WriteVarUInt16(value);
}
void OutputStream::WriteVarUInt32(System::UInt32 value)
{
m_impl->WriteVarUInt32(value);
}
void OutputStream::WriteVarUInt64(System::UInt64 value)
{
m_impl->WriteVarUInt64(value);
}
void OutputStream::WriteString(System::Text::Encoding^ encoding, System::String^ value, System::Int32 count)
{
auto ptr = m_impl->Allocate(count);
pin_ptr<const wchar_t> str = PtrToStringChars(value);
encoding->GetBytes(const_cast<wchar_t*>(str), value->Length, static_cast<unsigned char*>(ptr), count);
}
void OutputStream::WriteBytes(System::ArraySegment<System::Byte> data)
{
if (data.Array != nullptr && data.Count > 0)
{
pin_ptr<System::Byte> ptr = &data.Array[data.Offset];
m_impl->Write(ptr, data.Count);
}
}
BufferPool::ConstBuffer^ OutputStream::GetBuffer()
{
auto buffer = gcnew BufferPool::ConstBuffer{ std::move(*m_impl).GetBuffer() };
delete this;
return buffer;
}
} // Managed
} // Bond
} // IPC

38
Managed/Src/Transport.cpp Normal file
Просмотреть файл

@ -0,0 +1,38 @@
#include "IPC/Managed/detail/TransportImpl.h"
#include "BufferPool.h"
namespace IPC
{
namespace Managed
{
namespace detail
{
template <>
struct Convert<IPC::Bond::DefaultConstBuffer>
{
using type = IPC::Bond::Managed::BufferPool::ConstBuffer^;
static const IPC::Bond::DefaultConstBuffer& From(type% from)
{
return *from->Impl;
}
};
template <>
struct Convert<IPC::Bond::Managed::BufferPool::ConstBuffer^>
{
using type = IPC::Bond::DefaultConstBuffer;
static IPC::Bond::Managed::BufferPool::ConstBuffer^ From(const type& from)
{
return gcnew IPC::Bond::Managed::BufferPool::ConstBuffer{ from };
}
};
template Transport<IPC::Bond::Managed::BufferPool::ConstBuffer^, IPC::Bond::Managed::BufferPool::ConstBuffer^>;
} // detail
} // Managed
} // IPC

Просмотреть файл

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Inc\IPC\Bond\Accept.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Acceptor.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\BlobCast.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\BufferPool.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\BufferPoolFwd.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Client.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Connect.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Connector.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\DefaultTraits.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\detail\BlobHolder.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\detail\BufferPoolHolder.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\detail\ComponentBase.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\InputBuffer.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\OutputBuffer.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Serializer.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Server.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Transport.h" />
<ClInclude Include="..\Inc\stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Src\stdafx.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2030ED0D-4667-4299-87CD-ACE298BDF56D}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<TargetName>IPC.Bond</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<Lib>
<TargetMachine>MachineX64</TargetMachine>
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\..\Inc;..\Inc;..\..\bond\build\target\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets" Condition="Exists('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" />
<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('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="detail">
<UniqueIdentifier>{45e3f9ed-bd76-4f45-8e40-1d9c56304c65}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Src\stdafx.cpp">
<Filter>detail</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Inc\stdafx.h">
<Filter>detail</Filter>
</ClInclude>
<ClInclude Include="..\..\Inc\IPC\Bond\BufferPool.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\InputBuffer.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\OutputBuffer.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Client.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Server.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\DefaultTraits.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Acceptor.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Connector.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\detail\ComponentBase.h">
<Filter>detail</Filter>
</ClInclude>
<ClInclude Include="..\..\Inc\IPC\Bond\Accept.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Connect.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\BlobCast.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\detail\BlobHolder.h">
<Filter>detail</Filter>
</ClInclude>
<ClInclude Include="..\..\Inc\IPC\Bond\Serializer.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\detail\BufferPoolHolder.h">
<Filter>detail</Filter>
</ClInclude>
<ClInclude Include="..\..\Inc\IPC\Bond\BufferPoolFwd.h" />
<ClInclude Include="..\..\Inc\IPC\Bond\Transport.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.63.0.0" targetFramework="native" />
</packages>

3
Native/Inc/stdafx.h Normal file
Просмотреть файл

@ -0,0 +1,3 @@
#pragma once
#include <Windows.h>

1
Native/Src/stdafx.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "stdafx.h"

Просмотреть файл

@ -1,3 +1,28 @@
# IPC.Bond
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Microsoft/IPC/blob/master/LICENSE)
IPC.Bond is an extension of [IPC](https://github.com/Microsoft/IPC) library that provides inter-process communication using shared memory on Windows with [Bond](https://github.com/Microsoft/bond) serialization.<br/>
# Build
The library is developed and maintained with [Visual Studio 2015](https://msdn.microsoft.com/en-us/library/dd831853.aspx).
In order to build the library you will need to do the following:
1. Restore NuGet packages for [IPC.Bond.sln](https://github.com/Microsoft/IPC.Bond/blob/master/IPC.Bond.sln).
2. Build the [Bond](https://github.com/Microsoft/bond) (only core C++) submodule using helper [bond.cmd](https://github.com/Microsoft/IPC.Bond/blob/master/bond.cmd) script.
3. Build the [IPC](https://github.com/Microsoft/IPC) submodule using [IPC.sln](https://github.com/Microsoft/IPC/blob/master/IPC.sln).
4. Build the [IPC.Bond.sln](https://github.com/Microsoft/IPC.Bond/blob/master/IPC.Bond.sln).
# Getting Started
Start with [C++](https://github.com/Microsoft/IPC.Bond/blob/master/UnitTests/TransportTests.cpp) and [C#](https://github.com/Microsoft/IPC.Bond/blob/master/UnitTestsManaged/TransportTests.cs) tests.
# Contributing
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
# License
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the [MIT](https://github.com/Microsoft/IPC.Bond/blob/master/LICENSE) License.

73
Transport/AccessorBase.cs Normal file
Просмотреть файл

@ -0,0 +1,73 @@
using System;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public abstract class AccessorBase<T, Interface, InterfaceImpl, AccessorImpl> : Disposable<AccessorImpl>, IAccessor<Interface>
where Interface : class, IComponent
where InterfaceImpl : class, IComponent
where T : Interface
where AccessorImpl : class, IAccessor<InterfaceImpl>
{
internal AccessorBase(AccessorImpl impl)
: base(impl)
{
impl.Connected += OnConnected;
impl.Disconnected += OnDisconnected;
impl.Error += OnError;
}
protected abstract T ConnectComponent(InterfaceImpl impl);
protected abstract T DisconnectComponent(InterfaceImpl impl);
public event EventHandler<ComponentEventArgs<T>> Connected;
private event EventHandler<ComponentEventArgs<Interface>> ConnectedInternal;
event EventHandler<ComponentEventArgs<Interface>> IAccessor<Interface>.Connected
{
add { ConnectedInternal += value; }
remove { ConnectedInternal -= value; }
}
public event EventHandler<ComponentEventArgs<T>> Disconnected;
private event EventHandler<ComponentEventArgs<Interface>> DisconnectedInternal;
event EventHandler<ComponentEventArgs<Interface>> IAccessor<Interface>.Disconnected
{
add { DisconnectedInternal += value; }
remove { DisconnectedInternal -= value; }
}
public event EventHandler<ErrorEventArgs> Error;
private void OnConnected(object sender, ComponentEventArgs<InterfaceImpl> args)
{
var component = ConnectComponent(args.Component);
var connected = Connected;
connected?.Invoke(this, new ComponentEventArgs<T>(component));
var connectedInternal = ConnectedInternal;
connectedInternal?.Invoke(this, new ComponentEventArgs<Interface>(component));
}
private void OnDisconnected(object sender, ComponentEventArgs<InterfaceImpl> args)
{
var component = DisconnectComponent(args.Component);
var disconnected = Disconnected;
disconnected?.Invoke(this, new ComponentEventArgs<T>(component));
var disconnectedInternal = DisconnectedInternal;
disconnectedInternal?.Invoke(this, new ComponentEventArgs<Interface>(component));
}
private void OnError(object sender, ErrorEventArgs args)
{
var error = Error;
error?.Invoke(this, args);
}
}
}

18
Transport/AssemblyInfo.cs Normal file
Просмотреть файл

@ -0,0 +1,18 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("IPC.Bond.Managed.Transport")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("IPC.Bond.Managed")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.*")]

48
Transport/Client.cs Normal file
Просмотреть файл

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public class Client : Component, IClient<Request, Response>
{
private readonly Serializer _serializer;
internal Client(IClient<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl, Serializer serializer)
: base(impl)
{
_serializer = serializer;
}
/// <remarks>The caller is responsible for disposing the <param name="allocator"/></remarks>
public async Task<Response> InvokeAsync(Request request, TimeSpan timeout = default(TimeSpan))
{
Task<BufferPool.ConstBuffer> responseBufferTask;
using (var requestBuffer = _serializer.Serialize(request))
{
responseBufferTask = Impl.InvokeAsync(requestBuffer, timeout);
}
using (var responseBuffer = await responseBufferTask)
{
return _serializer.Deserialize<Response>(responseBuffer);
}
}
/// <remarks>The supplied allocator will be reclaimed by GC.</remarks>
Task<Response> IClient<Request, Response>.InvokeAsync(Request request, TimeSpan timeout)
{
return InvokeAsync(request, timeout);
}
private new IClient<BufferPool.ConstBuffer, BufferPool.ConstBuffer> Impl
{
get { return (IClient<BufferPool.ConstBuffer, BufferPool.ConstBuffer>)base.Impl; }
}
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
using System;
using System.Threading;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public class ClientAccessor :
AccessorBase<
Client,
IClient<Request, Response>,
IClient<BufferPool.ConstBuffer, BufferPool.ConstBuffer>,
IClientAccessor<BufferPool.ConstBuffer, BufferPool.ConstBuffer>>,
IClientAccessor<Request, Response>
{
private readonly Func<IComponent, Serializer> _serializerMaker;
private Client _client;
internal ClientAccessor(
IClientAccessor<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl,
Func<IComponent, Serializer> serializerMaker)
: base(impl)
{
_serializerMaker = serializerMaker;
}
public Client Client
{
get
{
return _client ?? ConnectComponent(Impl.Client);
}
}
IClient<Request, Response> IClientAccessor<Request, Response>.Client
{
get { return Client; }
}
protected override Client ConnectComponent(IClient<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
{
var client = new Client(impl, _serializerMaker(impl));
Interlocked.Exchange(ref _client, client);
return client;
}
protected override Client DisconnectComponent(IClient<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
{
return Interlocked.Exchange(ref _client, null);
}
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System;
using System.Threading.Tasks;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public class ClientConnector :
Disposable<IClientConnector<BufferPool.ConstBuffer, BufferPool.ConstBuffer>>,
IClientConnector<Request, Response>
{
private readonly Func<IComponent, Serializer> _serializerMaker;
internal ClientConnector(
IClientConnector<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl,
Func<IComponent, Serializer> serializerMaker)
: base(impl)
{
_serializerMaker = serializerMaker;
}
public async Task<Client> ConnectAsync(string acceptorName, TimeSpan timeout = default(TimeSpan))
{
var client = await Impl.ConnectAsync(acceptorName, timeout);
return new Client(client, _serializerMaker(client));
}
async Task<IClient<Request, Response>> IClientConnector<Request, Response>.ConnectAsync(string acceptorName, TimeSpan timeout)
{
return await ConnectAsync(acceptorName, timeout);
}
}
}
}

46
Transport/Component.cs Normal file
Просмотреть файл

@ -0,0 +1,46 @@
using System;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public abstract class Component : Disposable<IComponent>, IComponent
{
internal Component(IComponent impl)
: base(impl)
{
impl.Closed += OnClosed;
}
public SharedMemory InputMemory
{
get { return Impl.InputMemory; }
}
public SharedMemory OutputMemory
{
get { return Impl.OutputMemory; }
}
public bool IsClosed
{
get { return Impl.IsClosed; }
}
public event EventHandler Closed;
public void Close()
{
Impl.Close();
}
private void OnClosed(object sender, EventArgs args)
{
var closed = Closed;
closed?.Invoke(this, args);
}
}
}
}

11
Transport/Config.cs Normal file
Просмотреть файл

@ -0,0 +1,11 @@
namespace IPC.Bond.Managed
{
public class Config : IPC.Managed.Config
{
public global::Bond.ProtocolType ProtocolType { get; set; } = global::Bond.ProtocolType.COMPACT_PROTOCOL;
public bool Marshal { get; set; } = true;
public uint MinBlobSize { get; set; } = 0;
}
}

38
Transport/Disposable.cs Normal file
Просмотреть файл

@ -0,0 +1,38 @@
using System;
namespace IPC.Bond.Managed
{
public class Disposable<T> : IDisposable
where T : class, IDisposable
{
private T _impl;
internal Disposable(T impl)
{
_impl = impl;
}
internal T Impl
{
get { return _impl; }
}
protected virtual void Dispose(bool disposing)
{
if (_impl != null)
{
if (disposing)
{
_impl.Dispose();
}
_impl = null;
}
}
public void Dispose()
{
Dispose(true);
}
}
}

51
Transport/Serializer.cs Normal file
Просмотреть файл

@ -0,0 +1,51 @@
namespace IPC.Bond.Managed
{
using IPC.Managed;
public class Serializer
{
private readonly BufferPool _pool;
private readonly SharedMemory _inputMemory;
private readonly uint _minBlobSize;
private readonly ISerializer<InputStream, OutputStream> _serializer;
public Serializer(global::Bond.ProtocolType protocol, bool marshal, BufferPool pool, SharedMemory inputMemory, uint minBlobSize = 0)
: this(SerializerFactory.Create<InputStream, OutputStream>(protocol, marshal), pool, inputMemory, minBlobSize)
{ }
public Serializer(ISerializer<InputStream, OutputStream> serializer, BufferPool pool, SharedMemory inputMemory, uint minBlobSize = 0)
{
_pool = pool;
_inputMemory = inputMemory;
_minBlobSize = minBlobSize;
_serializer = serializer;
}
public global::Bond.ProtocolType ProtocolType
{
get { return _serializer.ProtocolType; }
}
public bool IsMarshaled
{
get { return _serializer.IsMarshaled; }
}
public BufferPool.ConstBuffer Serialize<T>(T obj)
{
using (var output = new OutputStream(_pool, _minBlobSize))
{
_serializer.Serialize(output, obj);
return output.GetBuffer();
}
}
public T Deserialize<T>(BufferPool.ConstBuffer buffer)
{
using (var input = new InputStream(buffer, _inputMemory))
{
return _serializer.Deserialize<T>(input);
}
}
}
}

Просмотреть файл

@ -0,0 +1,188 @@
namespace IPC.Bond.Managed
{
using IInputStream = global::Bond.IO.IInputStream;
using IOutputStream = global::Bond.IO.IOutputStream;
public interface ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
global::Bond.ProtocolType ProtocolType { get; }
bool IsMarshaled { get; }
void Serialize<T>(Output output, T obj);
T Deserialize<T>(Input input);
}
public struct CompactBinarySerializer<Input, Output> : ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
public global::Bond.ProtocolType ProtocolType
{
get { return global::Bond.ProtocolType.COMPACT_PROTOCOL; }
}
public bool IsMarshaled
{
get { return false; }
}
public void Serialize<T>(Output output, T obj)
{
global::Bond.Serialize.To(new global::Bond.Protocols.CompactBinaryWriter<Output>(output), obj);
}
public T Deserialize<T>(Input input)
{
return global::Bond.Deserialize<T>.From(new global::Bond.Protocols.CompactBinaryReader<Input>(input));
}
}
public struct FastBinarySerializer<Input, Output> : ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
public global::Bond.ProtocolType ProtocolType
{
get { return global::Bond.ProtocolType.FAST_PROTOCOL; }
}
public bool IsMarshaled
{
get { return false; }
}
public void Serialize<T>(Output output, T obj)
{
global::Bond.Serialize.To(new global::Bond.Protocols.FastBinaryWriter<Output>(output), obj);
}
public T Deserialize<T>(Input input)
{
return global::Bond.Deserialize<T>.From(new global::Bond.Protocols.FastBinaryReader<Input>(input));
}
}
public struct SimpleBinarySerializer<Input, Output> : ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
public global::Bond.ProtocolType ProtocolType
{
get { return global::Bond.ProtocolType.SIMPLE_PROTOCOL; }
}
public bool IsMarshaled
{
get { return false; }
}
public void Serialize<T>(Output output, T obj)
{
global::Bond.Serialize.To(new global::Bond.Protocols.SimpleBinaryWriter<Output>(output), obj);
}
public T Deserialize<T>(Input input)
{
return global::Bond.Deserialize<T>.From(new global::Bond.Protocols.SimpleBinaryReader<Input>(input));
}
}
public struct CompactBinaryMarshaler<Input, Output> : ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
public global::Bond.ProtocolType ProtocolType
{
get { return global::Bond.ProtocolType.COMPACT_PROTOCOL; }
}
public bool IsMarshaled
{
get { return true; }
}
public void Serialize<T>(Output output, T obj)
{
global::Bond.Marshal.To(new global::Bond.Protocols.CompactBinaryWriter<Output>(output), obj);
}
public T Deserialize<T>(Input input)
{
return global::Bond.Unmarshal<T>.From(input);
}
}
public struct FastBinaryMarshaler<Input, Output> : ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
public global::Bond.ProtocolType ProtocolType
{
get { return global::Bond.ProtocolType.FAST_PROTOCOL; }
}
public bool IsMarshaled
{
get { return true; }
}
public void Serialize<T>(Output output, T obj)
{
global::Bond.Marshal.To(new global::Bond.Protocols.FastBinaryWriter<Output>(output), obj);
}
public T Deserialize<T>(Input input)
{
return global::Bond.Unmarshal<T>.From(input);
}
}
public struct SimpleBinaryMarshaler<Input, Output> : ISerializer<Input, Output>
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
public global::Bond.ProtocolType ProtocolType
{
get { return global::Bond.ProtocolType.SIMPLE_PROTOCOL; }
}
public bool IsMarshaled
{
get { return true; }
}
public void Serialize<T>(Output output, T obj)
{
global::Bond.Marshal.To(new global::Bond.Protocols.SimpleBinaryWriter<Output>(output), obj);
}
public T Deserialize<T>(Input input)
{
return global::Bond.Unmarshal<T>.From(input);
}
}
public static class SerializerFactory
{
public static ISerializer<Input, Output> Create<Input, Output>(global::Bond.ProtocolType protocol, bool marshal)
where Input : IInputStream, global::Bond.IO.ICloneable<Input>
where Output : IOutputStream
{
switch (protocol)
{
case global::Bond.ProtocolType.COMPACT_PROTOCOL:
return marshal ? (ISerializer<Input, Output>)new CompactBinaryMarshaler<Input, Output>() : new CompactBinarySerializer<Input, Output>();
case global::Bond.ProtocolType.FAST_PROTOCOL:
return marshal ? (ISerializer<Input, Output>)new FastBinaryMarshaler<Input, Output>() : new FastBinarySerializer<Input, Output>();
case global::Bond.ProtocolType.SIMPLE_PROTOCOL:
return marshal ? (ISerializer<Input, Output>)new SimpleBinaryMarshaler<Input, Output>() : new SimpleBinarySerializer<Input, Output>();
}
throw new IPC.Managed.Exception("Unknown protocol.");
}
}
}

26
Transport/Server.cs Normal file
Просмотреть файл

@ -0,0 +1,26 @@
using System;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public class Server : Component, IServer<Request, Response>
{
internal Server(IServer<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
: base(impl)
{
impl.Error += OnError;
}
public event EventHandler<ErrorEventArgs> Error;
private void OnError(object sender, ErrorEventArgs args)
{
var error = Error;
error?.Invoke(this, args);
}
}
}
}

Просмотреть файл

@ -0,0 +1,49 @@
using System;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public class ServerAcceptor :
Disposable<IServerAcceptor<BufferPool.ConstBuffer, BufferPool.ConstBuffer>>,
IServerAcceptor<Request, Response>
{
internal ServerAcceptor(IServerAcceptor<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
: base(impl)
{
impl.Accepted += OnAccepted;
impl.Error += OnError;
}
public event EventHandler<ComponentEventArgs<Server>> Accepted;
private event EventHandler<ComponentEventArgs<IServer<Request, Response>>> AcceptedInternal;
event EventHandler<ComponentEventArgs<IServer<Request, Response>>> IServerAcceptor<Request, Response>.Accepted
{
add { AcceptedInternal += value; }
remove { AcceptedInternal -= value; }
}
public event EventHandler<ErrorEventArgs> Error;
private void OnAccepted(object sender, ComponentEventArgs<IServer<BufferPool.ConstBuffer, BufferPool.ConstBuffer>> args)
{
var server = new Server(args.Component);
var accepted = Accepted;
accepted?.Invoke(this, new ComponentEventArgs<Server>(server));
var acceptedInternal = AcceptedInternal;
acceptedInternal?.Invoke(this, new ComponentEventArgs<IServer<Request, Response>>(server));
}
private void OnError(object sender, ErrorEventArgs args)
{
var error = Error;
error?.Invoke(this, args);
}
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response>
{
public class ServersAccessor :
AccessorBase<
Server,
IServer<Request, Response>,
IServer<BufferPool.ConstBuffer, BufferPool.ConstBuffer>,
IServersAccessor<BufferPool.ConstBuffer, BufferPool.ConstBuffer>>,
IServersAccessor<Request, Response>
{
internal ServersAccessor(IServersAccessor<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
: base(impl)
{ }
public IReadOnlyCollection<Server> Servers
{
get
{
return new ReadOnlyCollection<Server>(Impl.Servers.Select(server => new Server(server)).ToList());
}
}
IReadOnlyCollection<IServer<Request, Response>> IServersAccessor<Request, Response>.Servers
{
get { return Servers; }
}
protected override Server ConnectComponent(IServer<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
{
return new Server(impl);
}
protected override Server DisconnectComponent(IServer<BufferPool.ConstBuffer, BufferPool.ConstBuffer> impl)
{
return new Server(impl);
}
}
}
}

105
Transport/Transport.cs Normal file
Просмотреть файл

@ -0,0 +1,105 @@
using System;
namespace IPC.Bond.Managed
{
using IPC.Managed;
public partial class Transport<Request, Response> :
Disposable<ITransport<BufferPool.ConstBuffer, BufferPool.ConstBuffer>>,
ITransport<Request, Response>
where Request : new()
where Response : new()
{
private static readonly TransportFactory _factory;
private readonly Config _config;
static Transport()
{
_factory = new TransportFactory();
_factory.Register(typeof(BufferPool).Assembly);
}
public Transport()
: this(new Config())
{ }
public Transport(Config config)
: base(_factory.Make<BufferPool.ConstBuffer, BufferPool.ConstBuffer>(config))
{
_config = config;
}
public ClientConnector MakeClientConnector()
{
return new ClientConnector(Impl.MakeClientConnector(), GetSerializerMaker());
}
IClientConnector<Request, Response> ITransport<Request, Response>.MakeClientConnector()
{
return MakeClientConnector();
}
public ServerAcceptor MakeServerAcceptor(string name, HandlerFactory<Request, Response> handlerFactory)
{
return new ServerAcceptor(Impl.MakeServerAcceptor(name, MakeHandlerFactory(handlerFactory)));
}
IServerAcceptor<Request, Response> ITransport<Request, Response>.MakeServerAcceptor(string name, HandlerFactory<Request, Response> handlerFactory)
{
return MakeServerAcceptor(name, handlerFactory);
}
public ClientAccessor ConnectClient(string name, bool async, TimeSpan timeout = default(TimeSpan), ClientConnector connector = null)
{
return new ClientAccessor(Impl.ConnectClient(name, async, timeout, connector?.Impl), GetSerializerMaker());
}
IClientAccessor<Request, Response> ITransport<Request, Response>.ConnectClient(
string name, bool async, TimeSpan timeout, IClientConnector<Request, Response> connector)
{
return ConnectClient(name, async, timeout, connector as ClientConnector);
}
public ServersAccessor AcceptServers(string name, HandlerFactory<Request, Response> handlerFactory)
{
return new ServersAccessor(Impl.AcceptServers(name, MakeHandlerFactory(handlerFactory)));
}
IServersAccessor<Request, Response> ITransport<Request, Response>.AcceptServers(string name, HandlerFactory<Request, Response> handlerFactory)
{
return AcceptServers(name, handlerFactory);
}
private Func<IComponent, Serializer> GetSerializerMaker()
{
return component => MakeSerializer(component.InputMemory, component.OutputMemory);
}
private Serializer MakeSerializer(SharedMemory inputMemory, SharedMemory outputMemory)
{
return new Serializer(_config.ProtocolType, _config.Marshal, new BufferPool(outputMemory), inputMemory, _config.MinBlobSize);
}
private HandlerFactory<BufferPool.ConstBuffer, BufferPool.ConstBuffer> MakeHandlerFactory(HandlerFactory<Request, Response> handlerFactory)
{
return (inputMemory, outputMemory) =>
{
var handler = handlerFactory(inputMemory, outputMemory);
var serializer = MakeSerializer(inputMemory, outputMemory);
return async (requestBuffer) =>
{
Request request;
using (requestBuffer)
{
request = serializer.Deserialize<Request>(requestBuffer);
}
return serializer.Serialize(await handler(request));
};
};
}
}
}

Просмотреть файл

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{BDAAAAAD-21A8-446E-840B-68718C49E7D4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>IPC.Bond.Managed</RootNamespace>
<AssemblyName>IPC.Bond.Managed.Transport</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<AssemblyClsCompliant>false</AssemblyClsCompliant>
<PlatformTarget>x64</PlatformTarget>
<TargetFrameworkProfile />
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\IPC.Bond.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<OutputPath>..\x64\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>..\x64\Release\</OutputPath>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="Bond">
<HintPath>..\IPC\Packages\Bond.Core.CSharp.6.0.0\lib\net45\Bond.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed">
<HintPath>..\IPC\$(Platform)\$(Configuration)\IPC.Managed.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed.Object">
<HintPath>..\IPC\$(Platform)\$(Configuration)\IPC.Managed.Object.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed.Transport">
<HintPath>..\IPC\$(Platform)\$(Configuration)\IPC.Managed.Transport.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Managed\Build\Managed.vcxproj">
<Project>{705098f7-93dc-4954-8165-fddcd66231f0}</Project>
<Name>Managed</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="AccessorBase.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Client.cs" />
<Compile Include="ClientAccessor.cs" />
<Compile Include="ClientConnector.cs" />
<Compile Include="Component.cs" />
<Compile Include="Config.cs" />
<Compile Include="Disposable.cs" />
<Compile Include="Serializer.cs" />
<Compile Include="SerializerFactory.cs" />
<Compile Include="Server.cs" />
<Compile Include="ServerAcceptor.cs" />
<Compile Include="ServersAccessor.cs" />
<Compile Include="Transport.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Bond.Core.CSharp" version="6.0.0" targetFramework="net46" />
</packages>

128
UnitTests/BlobCastTests.cpp Normal file
Просмотреть файл

@ -0,0 +1,128 @@
#include "stdafx.h"
#include "IPC/Bond/BlobCast.h"
#include "IPC/SharedMemory.h"
#include "IPC/detail/RandomString.h"
#include <memory>
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
using IPC::anonymous_instance;
BOOST_AUTO_TEST_SUITE(BlobCastTests)
struct BlobMock : public std::shared_ptr<std::pair<const char*, std::size_t>>
{
BlobMock() = default;
BlobMock(const char* data, std::size_t size)
: shared_ptr{ std::make_shared<std::pair<const char*, std::size_t>>(std::make_pair(data, size)) }
{}
const char* data() const
{
return get()->first;
}
std::size_t size() const
{
return get()->second;
}
BlobMock GetRange(std::size_t offset, std::size_t count) const
{
if (offset + count > size())
{
throw std::out_of_range{ "Count is out of range." };
}
return{ data() + offset, count };
}
};
BOOST_AUTO_TEST_CASE(CastToBondBlobTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024);
auto& data = memory->Construct<char[5]>(anonymous_instance);
std::strcpy(data, "Data");
BlobMock mock{ data, sizeof(data) };
BOOST_TEST(mock.unique());
bond::blob blob = BlobCast(mock, memory);
BOOST_TEST(blob.data() == data);
BOOST_TEST(blob.size() == sizeof(data));
BOOST_TEST(mock.use_count() == 2);
blob.clear();
BOOST_TEST(mock.unique());
}
BOOST_AUTO_TEST_CASE(CastToBondBlobMemoryOwnershipTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024);
auto& data = memory->Construct<char[5]>(anonymous_instance);
std::strcpy(data, "Data");
bond::blob blob;
{
BlobMock mock{ data, sizeof(data) };
BOOST_TEST(mock.unique());
BOOST_TEST(memory.unique());
blob = BlobCast(mock, memory);
}
BOOST_TEST(blob.data() == data);
BOOST_TEST(blob.size() == sizeof(data));
BOOST_TEST(memory.use_count() == 2);
memory.reset();
BOOST_TEST(std::strcmp(data, "Data") == 0);
}
BOOST_AUTO_TEST_CASE(CastFromCorrectBondBlobTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024);
auto& data = memory->Construct<char[5]>(anonymous_instance);
std::strcpy(data, "Data");
BlobMock mock = BlobCast<BlobMock>(BlobCast(BlobMock{ data, sizeof(data) }, memory));
BOOST_TEST(mock.data() == data);
BOOST_TEST(mock.size() == sizeof(data));
}
BOOST_AUTO_TEST_CASE(CastFromCorrectBondBlobWithOffsetTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024);
auto& data = memory->Construct<char[6]>(anonymous_instance);
std::strcpy(data, "Data!");
constexpr std::size_t offset = 2;
BlobMock mock = BlobCast<BlobMock>(BlobCast(BlobMock{ data, sizeof(data) }, memory).range(offset));
BOOST_TEST(mock.data() == data + offset);
BOOST_TEST(mock.size() == sizeof(data) - offset);
}
BOOST_AUTO_TEST_CASE(CastFromIncorrectBondBlobTest)
{
const char data[] = "Data";
BlobMock mock = BlobCast<BlobMock>(bond::blob{ data, sizeof(data) });
BOOST_TEST(!mock);
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,214 @@
#include "stdafx.h"
#include "IPC/Bond/BufferPool.h"
#include "IPC/detail/RandomString.h"
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
BOOST_AUTO_TEST_SUITE(BufferPoolTests)
static_assert(std::is_copy_constructible<DefaultBufferPool>::value, "BufferPool should be copy constructible.");
static_assert(std::is_copy_assignable<DefaultBufferPool>::value, "BufferPool should be copy assignable.");
static_assert(std::is_default_constructible<DefaultBufferPool::Blob>::value, "BufferPool::Blob should be default constructible.");
static_assert(!std::is_copy_constructible<DefaultBufferPool::Blob>::value, "BufferPool::Blob should not be copy constructible.");
static_assert(!std::is_copy_assignable<DefaultBufferPool::Blob>::value, "BufferPool::Blob should not be copy assignable.");
static_assert(std::is_move_constructible<DefaultBufferPool::Blob>::value, "BufferPool::Blob should be move constructible.");
static_assert(std::is_move_assignable<DefaultBufferPool::Blob>::value, "BufferPool::Blob should be move assignable.");
static_assert(std::is_default_constructible<DefaultBufferPool::ConstBlob>::value, "BufferPool::ConstBlob should be default constructible.");
static_assert(std::is_copy_constructible<DefaultBufferPool::ConstBlob>::value, "BufferPool::ConstBlob should be copy constructible.");
static_assert(std::is_copy_assignable<DefaultBufferPool::ConstBlob>::value, "BufferPool::ConstBlob should be copy assignable.");
static_assert(std::is_default_constructible<DefaultBufferPool::Buffer>::value, "BufferPool::Buffer should be default constructible.");
static_assert(!std::is_copy_constructible<DefaultBufferPool::Buffer>::value, "BufferPool::Buffer should not be copy constructible.");
static_assert(!std::is_copy_assignable<DefaultBufferPool::Buffer>::value, "BufferPool::Buffer should not be copy assignable.");
static_assert(std::is_move_constructible<DefaultBufferPool::Buffer>::value, "BufferPool::Buffer should be move constructible.");
static_assert(std::is_move_assignable<DefaultBufferPool::Buffer>::value, "BufferPool::Buffer should be move assignable.");
static_assert(std::is_default_constructible<DefaultBufferPool::ConstBuffer>::value, "BufferPool::ConstBuffer should be default constructible.");
static_assert(std::is_copy_constructible<DefaultBufferPool::ConstBuffer>::value, "BufferPool::ConstBuffer should be copy constructible.");
static_assert(std::is_copy_assignable<DefaultBufferPool::ConstBuffer>::value, "BufferPool::ConstBuffer should be copy assignable.");
static_assert(std::is_default_constructible<DefaultBufferPool::ConstBuffer::Range>::value, "BufferPool::ConstBuffer::Range should be default constructible.");
static_assert(std::is_copy_constructible<DefaultBufferPool::ConstBuffer::Range>::value, "BufferPool::ConstBuffer::Range should be copy constructible.");
static_assert(std::is_copy_assignable<DefaultBufferPool::ConstBuffer::Range>::value, "BufferPool::ConstBuffer::Range should be copy assignable.");
BOOST_AUTO_TEST_CASE(BlobTest)
{
auto name = GenerateRandomString();
auto memory = std::make_shared<SharedMemory>(create_only, name.c_str(), 1024 * 1024);
auto pool = std::make_unique<DefaultBufferPool>(memory);
auto blob = pool->TakeBlob();
BOOST_TEST(!!blob);
BOOST_TEST(blob->empty());
BOOST_TEST(&*blob == blob.operator->());
BOOST_CHECK_THROW((blob->resize(memory->GetFreeSize() + 1)), std::exception);
blob->resize(1024, boost::container::default_init);
BOOST_TEST(blob->size() == 1024);
BOOST_TEST(memory->Contains(blob->data()));
BOOST_TEST(memory->Contains(&*blob));
auto ptr = &*blob;
blob = {};
BOOST_TEST(!blob);
blob = pool->TakeBlob();
BOOST_TEST(!!blob);
BOOST_TEST(blob->empty());
BOOST_TEST(ptr == &*blob);
pool.reset();
BOOST_CHECK_NO_THROW(blob = {});
BOOST_TEST(!blob);
}
BOOST_AUTO_TEST_CASE(ConstBlobTest)
{
auto name = GenerateRandomString();
auto memory = std::make_shared<SharedMemory>(create_only, name.c_str(), 1024 * 1024);
auto pool = std::make_unique<DefaultBufferPool>(memory);
BOOST_TEST(!DefaultBufferPool::ConstBlob{});
auto blob = pool->TakeBlob();
blob->resize(1024, boost::container::default_init);
auto data = blob->data();
auto size = blob->size();
DefaultBufferPool::ConstBlob constBlob{ std::move(blob) };
BOOST_TEST(!!constBlob);
BOOST_TEST(constBlob.data() == data);
BOOST_TEST(constBlob.size() == size);
BOOST_TEST(&*constBlob.begin() == data);
BOOST_TEST(&*constBlob.end() == data + size);
BOOST_CHECK_THROW(constBlob.GetRange(1, size), std::exception);
BOOST_CHECK_THROW(constBlob.GetRange(size, 1), std::exception);
constexpr std::size_t offset = 2;
constexpr std::size_t count = 2;
auto range = constBlob.GetRange(offset, count);
BOOST_TEST(!!range);
BOOST_TEST(range.data() == data + offset);
BOOST_TEST(range.size() == count);
BOOST_TEST(&*range.begin() == data + offset);
BOOST_TEST(&*range.end() == data + offset + count);
}
BOOST_AUTO_TEST_CASE(BufferTest)
{
auto name = GenerateRandomString();
auto memory = std::make_shared<SharedMemory>(create_only, name.c_str(), 1024 * 1024);
auto pool = std::make_unique<DefaultBufferPool>(memory);
auto buffer = pool->TakeBuffer();
BOOST_TEST(!!buffer);
BOOST_TEST(buffer->empty());
BOOST_TEST(&*buffer == buffer.operator->());
BOOST_CHECK_THROW((buffer->resize(memory->GetFreeSize() + 1)), std::exception);
DefaultBufferPool::ConstBlob b1{ pool->TakeBlob() }, b2{ pool->TakeBlob() };
buffer->push_back(b1);
buffer->push_back(b2);
BOOST_TEST(buffer->size() == 2);
BOOST_TEST(memory->Contains(buffer->data()));
BOOST_TEST(memory->Contains(&*buffer));
auto ptr = &*buffer;
buffer = {};
BOOST_TEST(!buffer);
buffer = pool->TakeBuffer();
BOOST_TEST(!!buffer);
BOOST_TEST(buffer->empty());
BOOST_TEST(ptr == &*buffer);
pool.reset();
BOOST_CHECK_NO_THROW(buffer = {});
BOOST_TEST(!buffer);
}
BOOST_AUTO_TEST_CASE(ConstBufferTest)
{
auto name = GenerateRandomString();
auto memory = std::make_shared<SharedMemory>(create_only, name.c_str(), 1024 * 1024);
auto pool = std::make_unique<DefaultBufferPool>(memory);
BOOST_TEST(!DefaultBufferPool::ConstBuffer{});
auto buffer = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(100, boost::container::default_init);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(200, boost::container::default_init);
buffer->push_back(std::move(blob));
}
auto data = buffer->data();
auto size = buffer->size();
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
BOOST_TEST(!!constBuffer);
BOOST_TEST(&*constBuffer.begin() == data);
BOOST_TEST(&*constBuffer.end() == data + size);
BOOST_TEST(constBuffer.size() == 300);
BOOST_CHECK_NO_THROW((DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 }));
BOOST_TEST((constBuffer == constBuffer));
BOOST_TEST((DefaultBufferPool::ConstBuffer{} == DefaultBufferPool::ConstBuffer{}));
BOOST_TEST(!(constBuffer == DefaultBufferPool::ConstBuffer{}));
}
BOOST_AUTO_TEST_CASE(ConstBufferRangeTest)
{
auto name = GenerateRandomString();
auto memory = std::make_shared<SharedMemory>(create_only, name.c_str(), 1024 * 1024);
auto pool = std::make_unique<DefaultBufferPool>(memory);
BOOST_TEST(DefaultBufferPool::ConstBuffer::Range{}.IsEmpty());
{
auto buffer = pool->TakeBuffer();
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
BOOST_TEST((DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 }.IsEmpty()));
BOOST_TEST((DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 10, constBuffer.end(), 10 }.IsEmpty()));
}
{
auto buffer = pool->TakeBuffer();
buffer->push_back(pool->TakeBlob());
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
BOOST_TEST(!(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 }.IsEmpty()));
BOOST_TEST(!(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 10, constBuffer.end(), 10 }.IsEmpty()));
BOOST_TEST((DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.begin(), 0 }.IsEmpty()));
BOOST_TEST((DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 10, constBuffer.begin(), 10 }.IsEmpty()));
}
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<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>{2A3B9657-1D10-4A71-AA21-62AD4106CED4}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<TargetName>IPC.Bond.$(ProjectName)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;Synchronization.lib;..\..\IPC\$(Platform)\$(Configuration)\IPC.lib;..\..\bond\build\target\lib\bond\bond.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<TargetMachine>MachineX64</TargetMachine>
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\..\Inc;..\..\IPC\Inc;..\..\bond\build\target\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOND_COMPACT_BINARY_PROTOCOL;BOND_SIMPLE_BINARY_PROTOCOL;BOND_FAST_BINARY_PROTOCOL;BOND_SIMPLE_JSON_PROTOCOL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ItemGroup>
<ClCompile Include="..\BlobCastTests.cpp" />
<ClCompile Include="..\BufferPoolTests.cpp" />
<ClCompile Include="..\ClientServerTests.cpp" />
<ClCompile Include="..\ConnectAcceptTests.cpp" />
<ClCompile Include="..\InputBufferTests.cpp" />
<ClCompile Include="..\OutputBufferTests.cpp" />
<ClCompile Include="..\SerializerTests.cpp" />
<ClCompile Include="..\stdafx.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\TransportTests.cpp" />
<ClCompile Include="..\UsageTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\stdafx.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Native\Build\Native.vcxproj">
<Project>{2030ED0D-AAAA-4299-87CD-ACE298BDF56D}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets" Condition="Exists('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" />
<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('..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost.1.63.0.0\build\native\boost.targets'))" />
<Error Condition="!Exists('..\..\IPC\Packages\boost_unit_test_framework-vc140.1.63.0.0\build\native\boost_unit_test_framework-vc140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost_unit_test_framework-vc140.1.63.0.0\build\native\boost_unit_test_framework-vc140.targets'))" />
<Error Condition="!Exists('..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets'))" />
<Error Condition="!Exists('..\..\IPC\Packages\boost_locale-vc140.1.63.0.0\build\native\boost_locale-vc140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost_locale-vc140.1.63.0.0\build\native\boost_locale-vc140.targets'))" />
<Error Condition="!Exists('..\..\IPC\Packages\boost_thread-vc140.1.63.0.0\build\native\boost_thread-vc140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost_thread-vc140.1.63.0.0\build\native\boost_thread-vc140.targets'))" />
<Error Condition="!Exists('..\..\IPC\Packages\boost_system-vc140.1.63.0.0\build\native\boost_system-vc140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\IPC\Packages\boost_system-vc140.1.63.0.0\build\native\boost_system-vc140.targets'))" />
</Target>
<Import Project="..\..\IPC\Packages\boost_unit_test_framework-vc140.1.63.0.0\build\native\boost_unit_test_framework-vc140.targets" Condition="Exists('..\..\IPC\Packages\boost_unit_test_framework-vc140.1.63.0.0\build\native\boost_unit_test_framework-vc140.targets')" />
<Import Project="..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets" Condition="Exists('..\..\IPC\Packages\boost_date_time-vc140.1.63.0.0\build\native\boost_date_time-vc140.targets')" />
<Import Project="..\..\IPC\Packages\boost_locale-vc140.1.63.0.0\build\native\boost_locale-vc140.targets" Condition="Exists('..\..\IPC\Packages\boost_locale-vc140.1.63.0.0\build\native\boost_locale-vc140.targets')" />
<Import Project="..\..\IPC\Packages\boost_thread-vc140.1.63.0.0\build\native\boost_thread-vc140.targets" Condition="Exists('..\..\IPC\Packages\boost_thread-vc140.1.63.0.0\build\native\boost_thread-vc140.targets')" />
<Import Project="..\..\IPC\Packages\boost_system-vc140.1.63.0.0\build\native\boost_system-vc140.targets" Condition="Exists('..\..\IPC\Packages\boost_system-vc140.1.63.0.0\build\native\boost_system-vc140.targets')" />
</Project>

Просмотреть файл

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\stdafx.cpp" />
<ClCompile Include="..\BlobCastTests.cpp" />
<ClCompile Include="..\BufferPoolTests.cpp" />
<ClCompile Include="..\OutputBufferTests.cpp" />
<ClCompile Include="..\InputBufferTests.cpp" />
<ClCompile Include="..\SerializerTests.cpp" />
<ClCompile Include="..\ClientServerTests.cpp" />
<ClCompile Include="..\ConnectAcceptTests.cpp" />
<ClCompile Include="..\UsageTests.cpp" />
<ClCompile Include="..\TransportTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\stdafx.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.63.0.0" targetFramework="native" />
<package id="boost_date_time-vc140" version="1.63.0.0" targetFramework="native" />
<package id="boost_locale-vc140" version="1.63.0.0" targetFramework="native" />
<package id="boost_system-vc140" version="1.63.0.0" targetFramework="native" />
<package id="boost_thread-vc140" version="1.63.0.0" targetFramework="native" />
<package id="boost_unit_test_framework-vc140" version="1.63.0.0" targetFramework="native" />
</packages>

Просмотреть файл

@ -0,0 +1,204 @@
#include "stdafx.h"
#include "IPC/Bond/Server.h"
#include "IPC/Bond/Client.h"
#include "IPC/Bond/Acceptor.h"
#include "IPC/Bond/Connector.h"
#include "IPC/detail/RandomString.h"
#include <bond/core/tuple.h>
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
BOOST_AUTO_TEST_SUITE(ClientServerTests)
using Request = std::tuple<int>;
using Response = std::tuple<int, int>;
class SerializerMock
{
public:
template <typename T>
DefaultBufferPool::ConstBuffer Serialize(const T& value);
template <>
DefaultBufferPool::ConstBuffer Serialize(const Request& /*value*/)
{
++m_counters->m_requestSerialized;
return{};
}
template <>
DefaultBufferPool::ConstBuffer Serialize(const Response& /*value*/)
{
++m_counters->m_responseSerialized;
return{};
}
template <typename T>
void Deserialize(DefaultBufferPool::ConstBuffer&& buffer, T& value);
template <>
void Deserialize(DefaultBufferPool::ConstBuffer&& /*buffer*/, Response& /*value*/)
{
++m_counters->m_responseDeserialized;
}
template <typename T>
std::future<T> Deserialize(DefaultBufferPool::ConstBuffer buffer);
template <>
std::future<Request> Deserialize(DefaultBufferPool::ConstBuffer /*buffer*/)
{
++m_counters->m_requestDeserialized;
return Deserialize<Request>();
}
template <>
std::future<Response> Deserialize(DefaultBufferPool::ConstBuffer /*buffer*/)
{
++m_counters->m_responseDeserialized;
return Deserialize<Response>();
}
bool CheckClientUsage() const
{
return m_counters->m_requestSerialized == 1
&& m_counters->m_requestDeserialized == 0
&& m_counters->m_responseSerialized == 0
&& m_counters->m_responseDeserialized == 1;
}
bool CheckServerUsage() const
{
return m_counters->m_requestSerialized == 0
&& m_counters->m_requestDeserialized == 1
&& m_counters->m_responseSerialized == 1
&& m_counters->m_responseDeserialized == 0;
}
void ResetCounters()
{
m_counters->Reset();
}
private:
template <typename T>
std::future<T> Deserialize()
{
std::promise<T> promise;
promise.set_value({});
return promise.get_future();
}
struct Counters
{
void Reset()
{
*this = {};
}
std::size_t m_requestSerialized{ 0 };
std::size_t m_requestDeserialized{ 0 };
std::size_t m_responseSerialized{ 0 };
std::size_t m_responseDeserialized{ 0 };
};
std::shared_ptr<Counters> m_counters{ std::make_shared<Counters>() };
};
struct MockTraits : DefaultTraits
{
using Serializer = SerializerMock;
};
using Server = Server<Request, Response, MockTraits>;
using Client = Client<Request, Response, MockTraits>;
using Acceptor = ServerAcceptor<Request, Response, MockTraits>;
using Connector = ClientConnector<Request, Response, MockTraits>;
BOOST_AUTO_TEST_CASE(SerializerTest)
{
auto name = GenerateRandomString();
std::unique_ptr<Server> server;
Acceptor acceptor{
name.c_str(),
[&](auto&& futureConnection)
{
server = std::make_unique<Server>(
detail::BufferPoolHolder<DefaultBufferPool>{ nullptr, nullptr },
SerializerMock{},
futureConnection.get(),
[](auto futureRequest, auto&& callback)
{
auto request = futureRequest.get();
callback(std::tuple_cat(request, request));
},
[] {});
} };
Client client{
detail::BufferPoolHolder<DefaultBufferPool>{ nullptr, nullptr },
SerializerMock{},
Connector{}.Connect(name.c_str()).get(),
[] {},
{} };
std::promise<Response> result;
client(Request{}, [&](std::future<Response>&& response) { result.set_value(response.get()); });
BOOST_TEST((result.get_future().get() == Response{}));
BOOST_TEST(client.CheckClientUsage());
BOOST_TEST(server->CheckServerUsage());
client.ResetCounters();
server->ResetCounters();
BOOST_TEST((client(Request{}).get() == Response{}));
BOOST_TEST(client.CheckClientUsage());
BOOST_TEST(server->CheckServerUsage());
client.ResetCounters();
server->ResetCounters();
BOOST_TEST((client(Request{}, std::chrono::milliseconds{ 1 }).get() == Response{}));
BOOST_TEST(client.CheckClientUsage());
BOOST_TEST(server->CheckServerUsage());
}
BOOST_AUTO_TEST_CASE(BufferPoolTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024);
auto inPool = std::make_shared<DefaultBufferPool>(memory);
auto outPool = std::make_shared<DefaultBufferPool>(memory);
auto name = GenerateRandomString();
std::unique_ptr<Server> server;
Acceptor acceptor{
name.c_str(),
[&](auto&& futureConnection)
{
server = std::make_unique<Server>(
detail::BufferPoolHolder<DefaultBufferPool>{ inPool, outPool },
SerializerMock{},
futureConnection.get(),
[](auto&&...) {},
[] {});
} };
Client client{
detail::BufferPoolHolder<DefaultBufferPool>{ inPool, outPool },
SerializerMock{},
Connector{}.Connect(name.c_str()).get(),
[] {} };
BOOST_TEST(client.GetInputPool() == inPool);
BOOST_TEST(client.GetOutputPool() == outPool);
BOOST_TEST(server->GetInputPool() == inPool);
BOOST_TEST(server->GetOutputPool() == outPool);
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,183 @@
#include "stdafx.h"
#include "IPC/Bond/Accept.h"
#include "IPC/Bond/Connect.h"
#include "IPC/Bond/Connector.h"
#include "IPC/detail/RandomString.h"
#include <bond/core/bond.h>
#include <bond/protocol/simple_json_writer.h>
#include <bond/core/tuple.h>
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
BOOST_AUTO_TEST_SUITE(ConnectAcceptTests)
using Request = std::tuple<int>;
using Response = std::tuple<int, int>;
class SerializerMock : public DefaultSerializer
{
public:
SerializerMock(
bond::ProtocolType protocol,
bool marshal,
std::shared_ptr<DefaultBufferPool> outputPool,
std::shared_ptr<SharedMemory> inputMemory = {},
std::size_t minBlobSize = 0)
: DefaultSerializer{ protocol, marshal, outputPool, std::move(inputMemory), minBlobSize },
m_outputPool{ std::move(outputPool) }
{}
const auto& GetSerializerPool() const
{
return m_outputPool;
}
private:
std::shared_ptr<DefaultBufferPool> m_outputPool;
};
struct MockTraits : DefaultTraits
{
using Serializer = SerializerMock;
};
using ClientConnector = ClientConnector<Request, Response, MockTraits>;
using ServerConnector = ServerConnector<Request, Response, MockTraits>;
BOOST_AUTO_TEST_CASE(SerializerTest)
{
auto name = GenerateRandomString();
auto serversAccessor = AcceptServers<Request, Response, MockTraits>(
name.c_str(),
[](auto&&...) { return [](auto&&...) {}; });
auto clientAccessor = ConnectClient(name.c_str(), std::make_shared<ClientConnector>(), false);
while (true)
{
auto servers = serversAccessor();
if (servers->empty())
{
std::this_thread::yield();
continue;
}
const auto& server = servers->front();
BOOST_TEST(server->GetSerializerPool() == server->GetOutputPool());
break;
}
auto client = clientAccessor();
BOOST_TEST(client->GetSerializerPool() == client->GetOutputPool());
}
BOOST_AUTO_TEST_CASE(ReverseConnectionSerializerTest)
{
auto name = GenerateRandomString();
auto clientsAccessor = AcceptClients<Request, Response, MockTraits>(name.c_str());
auto serverAccessor = ConnectServer(
name.c_str(),
std::make_shared<ServerConnector>(),
[](auto&&...) { return [](auto&&...) {}; },
false);
while (true)
{
auto clients = clientsAccessor();
if (clients->empty())
{
std::this_thread::yield();
continue;
}
const auto& client = clients->front();
BOOST_TEST(client->GetSerializerPool() == client->GetOutputPool());
break;
}
auto server = serverAccessor();
BOOST_TEST(server->GetSerializerPool() == server->GetOutputPool());
}
BOOST_AUTO_TEST_CASE(BufferPoolTest)
{
auto name = GenerateRandomString();
auto serversAccessor = AcceptServers<Request, Response, MockTraits>(
name.c_str(),
[](auto&&...) { return [](auto&&...) {}; });
auto clientAccessor = ConnectClient(name.c_str(), std::make_shared<ClientConnector>(), false);
while (true)
{
auto servers = serversAccessor();
if (servers->empty())
{
std::this_thread::yield();
continue;
}
const auto& server = servers->front();
BOOST_TEST(server->GetConnection().GetInputChannel().GetMemory() == server->GetInputPool()->GetMemory());
BOOST_TEST(server->GetConnection().GetOutputChannel().GetMemory() == server->GetOutputPool()->GetMemory());
break;
}
auto client = clientAccessor();
BOOST_TEST(client->GetConnection().GetInputChannel().GetMemory() == client->GetInputPool()->GetMemory());
BOOST_TEST(client->GetConnection().GetOutputChannel().GetMemory() == client->GetOutputPool()->GetMemory());
}
BOOST_AUTO_TEST_CASE(ReverseConnectionBufferPoolTest)
{
auto name = GenerateRandomString();
auto clientsAccessor = AcceptClients<Request, Response, MockTraits>(name.c_str());
auto serverAccessor = ConnectServer(
name.c_str(),
std::make_shared<ServerConnector>(),
[](auto&&...) { return [](auto&&...) {}; },
false);
while (true)
{
auto clients = clientsAccessor();
if (clients->empty())
{
std::this_thread::yield();
continue;
}
const auto& client = clients->front();
BOOST_TEST(client->GetConnection().GetInputChannel().GetMemory() == client->GetInputPool()->GetMemory());
BOOST_TEST(client->GetConnection().GetOutputChannel().GetMemory() == client->GetOutputPool()->GetMemory());
break;
}
auto server = serverAccessor();
BOOST_TEST(server->GetConnection().GetInputChannel().GetMemory() == server->GetInputPool()->GetMemory());
BOOST_TEST(server->GetConnection().GetOutputChannel().GetMemory() == server->GetOutputPool()->GetMemory());
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,460 @@
#include "stdafx.h"
#include "IPC/Bond/InputBuffer.h"
#include "IPC/detail/RandomString.h"
#include <tuple>
#include <type_traits>
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
BOOST_AUTO_TEST_SUITE(InputBufferTests)
static_assert(std::is_default_constructible<DefaultInputBuffer>::value, "InputBuffer should be default constructible.");
static_assert(std::is_copy_constructible<DefaultInputBuffer>::value, "InputBuffer should be copy constructible.");
static_assert(std::is_copy_assignable<DefaultInputBuffer>::value, "InputBuffer should be copy assignable.");
template <typename Function, std::size_t... I>
void ForEach(Function&& func, std::index_sequence<I...>)
{
auto dummy = { (func(std::integral_constant<std::size_t, I>{}), 0)... };
(void)dummy;
}
BOOST_AUTO_TEST_CASE(ReadTrivialTypesTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
auto values = std::make_tuple(
static_cast<std::int8_t>(1),
static_cast<std::int16_t>(2),
static_cast<std::int32_t>(3),
static_cast<std::int64_t>(4),
static_cast<std::uint8_t>(5),
static_cast<std::uint16_t>(6),
static_cast<std::uint32_t>(7),
static_cast<std::uint64_t>(8),
static_cast<float>(9.10),
static_cast<double>(11.12));
ForEach(
[&](auto index)
{
auto& value = std::get<index.value>(values);
(void)index;
auto blob = pool->TakeBlob();
blob->resize(sizeof(decltype(value)), boost::container::default_init);
std::memcpy(blob->data(), &value, sizeof(value));
buffer->push_back(std::move(blob));
},
std::make_index_sequence<std::tuple_size<decltype(values)>::value>{});
DefaultInputBuffer input{ std::move(buffer), pool->GetMemory() };
decltype(values) results;
BOOST_TEST(!input.IsEof());
ForEach(
[&](auto index)
{
input.Read(std::get<index.value>(results));
(void)index;
},
std::make_index_sequence<std::tuple_size<decltype(values)>::value>{});
BOOST_TEST(input.IsEof());
BOOST_TEST((values == results));
}
BOOST_AUTO_TEST_CASE(ReadRawBytesTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(20, 2);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(30, 3);
buffer->push_back(std::move(blob));
}
DefaultInputBuffer input{ std::move(buffer), pool->GetMemory() };
char result[10 + 20 + 30];
auto ptr = result;
input.Read(ptr, 5);
input.Read(ptr += 5, 10);
input.Read(ptr += 10, 5);
BOOST_CHECK_THROW(input.Read(ptr += 5, 41), std::exception);
input.Read(ptr, 15);
input.Read(ptr += 15, 5);
input.Read(ptr += 5, 20);
BOOST_TEST(input.IsEof());
BOOST_TEST(std::all_of(result, result + 10, [](const char& c) { return c == 1; }));
BOOST_TEST(std::all_of(result + 10, result + 10 + 20, [](const char& c) { return c == 2; }));
BOOST_TEST(std::all_of(result + 10 + 20, result + 10 + 20 + 30, [](const char& c) { return c == 3; }));
}
BOOST_AUTO_TEST_CASE(ReadBondBlobTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(10, 2);
buffer->push_back(std::move(blob));
}
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
DefaultInputBuffer input{ constBuffer, pool->GetMemory() };
bond::blob b1, b2, b3;
BOOST_CHECK_THROW(input.Read(b1, 20), std::exception);
input.Read(b1, 5);
input.Read(b2, 5);
input.Read(b3, 10);
BOOST_TEST(input.IsEof());
BOOST_TEST(b1.size() == 5U);
BOOST_TEST(std::all_of(b1.begin(), b1.end(), [](const char& c) { return c == 1; }));
BOOST_TEST(b2.size() == 5U);
BOOST_TEST(std::all_of(b2.begin(), b2.end(), [](const char& c) { return c == 1; }));
BOOST_TEST(b3.size() == 10U);
BOOST_TEST(std::all_of(b3.begin(), b3.end(), [](const char& c) { return c == 2; }));
BOOST_TEST(BlobCast<DefaultBufferPool::ConstBlob>(b1).data() == constBuffer.begin()->data());
BOOST_TEST(BlobCast<DefaultBufferPool::ConstBlob>(b2).data() == constBuffer.begin()->data() + 5);
BOOST_TEST(BlobCast<DefaultBufferPool::ConstBlob>(b3).data() == std::next(constBuffer.begin())->data());
}
BOOST_AUTO_TEST_CASE(SkipTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(10, 2);
buffer->push_back(std::move(blob));
}
DefaultInputBuffer input{ std::move(buffer), pool->GetMemory() };
char result[10];
input.Read(result, 5);
BOOST_CHECK_THROW(input.Skip(16), std::exception);
input.Skip(10);
input.Read(result + 5, 5);
BOOST_TEST(input.IsEof());
BOOST_TEST(std::all_of(result, result + 5, [](const char& c) { return c == 1; }));
BOOST_TEST(std::all_of(result + 5, result + 10, [](const char& c) { return c == 2; }));
BOOST_CHECK_NO_THROW(input.Skip(0));
BOOST_CHECK_THROW(input.Skip(1), std::exception);
}
BOOST_AUTO_TEST_CASE(ReadEmptyDataTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
buffer->push_back(DefaultBufferPool::ConstBlob{});
buffer->push_back(pool->TakeBlob());
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
BOOST_TEST((DefaultInputBuffer{ DefaultBufferPool::ConstBuffer{}, nullptr }.IsEof()));
BOOST_TEST((DefaultInputBuffer{ constBuffer, pool->GetMemory() }.IsEof()));
BOOST_TEST((DefaultInputBuffer{ DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 }, pool->GetMemory() }.IsEof()));
BOOST_TEST((DefaultInputBuffer{ DefaultBufferPool::ConstBuffer::Range{}, nullptr }.IsEof()));
}
BOOST_AUTO_TEST_CASE(ReadFromRangeTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(20, 2);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(30, 3);
buffer->push_back(std::move(blob));
}
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
{
DefaultInputBuffer input{ DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 }, pool->GetMemory() };
char result[10 + 20 + 30];
BOOST_TEST(!input.IsEof());
input.Read(result, sizeof(result));
BOOST_TEST(input.IsEof());
BOOST_TEST(std::all_of(result, result + 10, [](const char& c) { return c == 1; }));
BOOST_TEST(std::all_of(result + 10, result + 10 + 20, [](const char& c) { return c == 2; }));
BOOST_TEST(std::all_of(result + 10 + 20, result + 10 + 20 + 30, [](const char& c) { return c == 3; }));
}
{
DefaultInputBuffer input{ DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 3, constBuffer.begin(), 8 }, pool->GetMemory() };
char result[5];
BOOST_TEST(!input.IsEof());
input.Read(result, sizeof(result));
BOOST_TEST(input.IsEof());
BOOST_TEST(std::all_of(result, result + 5, [](const char& c) { return c == 1; }));
}
{
DefaultInputBuffer input{ DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 5, std::next(constBuffer.begin(), 2), 15 }, pool->GetMemory() };
char result[5 + 20 + 15];
BOOST_TEST(!input.IsEof());
input.Read(result, sizeof(result));
BOOST_TEST(input.IsEof());
BOOST_TEST(std::all_of(result, result + 5, [](const char& c) { return c == 1; }));
BOOST_TEST(std::all_of(result + 5, result + 5 + 20, [](const char& c) { return c == 2; }));
BOOST_TEST(std::all_of(result + 5 + 20, result + 5 + 20 + 15, [](const char& c) { return c == 3; }));
}
}
BOOST_AUTO_TEST_CASE(IsEofTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
auto blob = pool->TakeBlob();
blob->resize(10);
buffer->push_back(std::move(blob));
DefaultInputBuffer input{ std::move(buffer), pool->GetMemory() };
BOOST_TEST(DefaultInputBuffer{}.IsEof());
BOOST_TEST(!input.IsEof());
input.Skip(5);
BOOST_TEST(!input.IsEof());
BOOST_CHECK_THROW(input.Skip(10), std::exception);
BOOST_TEST(!input.IsEof());
input.Skip(5);
BOOST_TEST(input.IsEof());
}
BOOST_AUTO_TEST_CASE(EqualityTest)
{
BOOST_TEST((DefaultInputBuffer{ DefaultBufferPool::ConstBuffer{}, nullptr } == DefaultInputBuffer{ DefaultBufferPool::ConstBuffer{}, nullptr }));
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer1 = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10);
buffer1->push_back(std::move(blob));
}
auto buffer2 = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10);
buffer2->push_back(std::move(blob));
}
assert(buffer1->size() == 1);
assert(buffer2->size() == 1);
assert(std::equal(buffer1->front().begin(), buffer1->front().end(), buffer2->front().begin(), buffer2->front().end()));
DefaultInputBuffer input1{ std::move(buffer1), pool->GetMemory() };
auto input1Copy = input1;
DefaultInputBuffer input2{ std::move(buffer2), pool->GetMemory() };
auto input2Copy = input2;
BOOST_TEST(!(input1 == input2));
BOOST_TEST(!(input1Copy == input2Copy));
BOOST_TEST((input1 == input1Copy));
BOOST_TEST((input2 == input2Copy));
}
BOOST_AUTO_TEST_CASE(GetCurrentBufferTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
auto blob = pool->TakeBlob();
blob->resize(10);
buffer->push_back(std::move(blob));
DefaultInputBuffer input{ std::move(buffer), pool->GetMemory() };
BOOST_TEST((GetCurrentBuffer(input) == input));
}
BOOST_AUTO_TEST_CASE(GetBufferRangeTest)
{
BOOST_TEST(GetBufferRange(
DefaultInputBuffer{ DefaultBufferPool::ConstBuffer{}, nullptr },
DefaultInputBuffer{ DefaultBufferPool::ConstBuffer{}, nullptr }).IsEmpty());
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
{
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
}
{
auto blob = pool->TakeBlob();
blob->resize(20, 2);
buffer->push_back(std::move(blob));
}
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
DefaultInputBuffer input1{ constBuffer, pool->GetMemory() };
DefaultInputBuffer input2{ constBuffer, pool->GetMemory() };
input1.Skip(5);
input2.Skip(20);
{
DefaultInputBuffer input3{ GetBufferRange(input1, input2), pool->GetMemory() };
char result[15];
BOOST_TEST(!input3.IsEof());
input3.Read(result, sizeof(result));
BOOST_TEST(input3.IsEof());
BOOST_TEST(std::all_of(result, result + 5, [](const char& c) { return c == 1; }));
BOOST_TEST(std::all_of(result + 5, result + 15, [](const char& c) { return c == 2; }));
}
input1.Skip(10);
input2.Skip(5);
{
DefaultInputBuffer input3{ GetBufferRange(input1, input2), pool->GetMemory() };
char result[10];
BOOST_TEST(!input3.IsEof());
input3.Read(result, sizeof(result));
BOOST_TEST(input3.IsEof());
BOOST_TEST(std::all_of(result, result + 10, [](const char& c) { return c == 2; }));
}
input2.Skip(5);
assert(input2.IsEof());
{
DefaultInputBuffer input3{ GetBufferRange(input1, input2), pool->GetMemory() };
char result[15];
BOOST_TEST(!input3.IsEof());
input3.Read(result, sizeof(result));
BOOST_TEST(input3.IsEof());
BOOST_TEST(std::all_of(result, result + 15, [](const char& c) { return c == 2; }));
}
input1.Skip(15);
assert(input1.IsEof());
{
DefaultInputBuffer input3{ GetBufferRange(input1, input2), pool->GetMemory() };
BOOST_TEST(input3.IsEof());
BOOST_CHECK_THROW(input3.Skip(1), std::exception);
}
}
BOOST_AUTO_TEST_CASE(CreateInputBufferTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto buffer = pool->TakeBuffer();
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
auto input = CreateInputBuffer(
DefaultInputBuffer{ constBuffer, pool->GetMemory() },
DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 3, constBuffer.begin(), 8 });
char result[5];
BOOST_TEST(!input.IsEof());
input.Read(result, sizeof(result));
BOOST_TEST(input.IsEof());
BOOST_TEST(std::all_of(result, result + 5, [](const char& c) { return c == 1; }));
}
BOOST_AUTO_TEST_CASE(MemoryOwnershipTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024);
bond::blob bondBlob;
const char* ptr;
BOOST_TEST(memory.unique());
{
DefaultBufferPool::ConstBuffer constBuffer;
{
auto pool = std::make_shared<DefaultBufferPool>(memory);
auto buffer = pool->TakeBuffer();
auto blob = pool->TakeBlob();
blob->resize(10, 1);
buffer->push_back(std::move(blob));
constBuffer = std::move(buffer);
}
DefaultInputBuffer input{ constBuffer, memory };
BOOST_TEST(memory.use_count() == 2);
input.Read(bondBlob, 10);
BOOST_TEST(memory.use_count() == 3);
ptr = constBuffer.begin()->data();
}
BOOST_TEST(bondBlob.data() == ptr);
BOOST_TEST(memory.use_count() == 2);
memory.reset();
BOOST_TEST(std::all_of(ptr, ptr + 10, [](const char& c) { return c == 1; }));
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,460 @@
#include "stdafx.h"
#include "IPC/Bond/OutputBuffer.h"
#include "IPC/detail/RandomString.h"
#include <tuple>
#include <type_traits>
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
BOOST_AUTO_TEST_SUITE(OutputBufferTests)
static_assert(!std::is_copy_constructible<DefaultOutputBuffer>::value, "OutputBuffer should not be copy constructible.");
static_assert(!std::is_copy_assignable<DefaultOutputBuffer>::value, "OutputBuffer should not be copy assignable.");
static_assert(std::is_move_constructible<DefaultOutputBuffer>::value, "OutputBuffer should be move constructible.");
static_assert(std::is_move_assignable<DefaultOutputBuffer>::value, "OutputBuffer should be move assignable.");
template <typename Function, std::size_t... I>
void ForEach(Function&& func, std::index_sequence<I...>)
{
auto dummy = { (func(std::integral_constant<std::size_t, I>{}), 0)... };
(void)dummy;
}
BOOST_AUTO_TEST_CASE(WriteArithmeticTypesTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool, 3 };
auto values = std::make_tuple(
static_cast<std::int8_t>(1),
static_cast<std::int16_t>(2),
static_cast<std::int32_t>(3),
static_cast<std::int64_t>(4),
static_cast<std::uint8_t>(5),
static_cast<std::uint16_t>(6),
static_cast<std::uint32_t>(7),
static_cast<std::uint64_t>(8),
static_cast<float>(9.10),
static_cast<double>(11.12));
std::size_t size = 0;
ForEach(
[&](auto index)
{
const auto& value = std::get<index.value>(values);
(void)index;
output.Write(value);
size += sizeof(decltype(value));
},
std::make_index_sequence<std::tuple_size<decltype(values)>::value>{});
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == size);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
auto ptr = buffer.begin()->data();
ForEach(
[&](auto index)
{
const auto& value = std::get<index.value>(values);
(void)index;
BOOST_TEST(std::memcmp(&value, ptr, sizeof(value)) == 0);
ptr += sizeof(decltype(value));
},
std::make_index_sequence<std::tuple_size<decltype(values)>::value>{});
}
BOOST_AUTO_TEST_CASE(WriteRawBytesTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool, 2 };
const char data[] = "Data";
output.Write(data, sizeof(data));
output.Write(data, sizeof(data));
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == 2 * sizeof(data));
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
auto ptr = buffer.begin()->data();
BOOST_TEST(std::memcmp(ptr, data, sizeof(data)) == 0);
BOOST_TEST(std::memcmp(ptr + sizeof(data), data, sizeof(data)) == 0);
}
BOOST_AUTO_TEST_CASE(WriteBufferTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool, 3 };
const char data[] = "Data";
output.Write(data, sizeof(data));
DefaultBufferPool::ConstBlob b1;
{
auto blob = pool->TakeBlob();
blob->resize(10);
b1 = std::move(blob);
}
DefaultBufferPool::ConstBlob b2;
{
auto blob = pool->TakeBlob();
blob->resize(20);
b2 = std::move(blob);
}
{
auto buffer = pool->TakeBuffer();
buffer->push_back(b1);
buffer->push_back(DefaultBufferPool::ConstBlob{ pool->TakeBlob() });
buffer->push_back(b2);
buffer->push_back(DefaultBufferPool::ConstBlob{});
output.Write(DefaultBufferPool::ConstBuffer{ std::move(buffer) });
}
auto otherPool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
{
auto buffer = otherPool->TakeBuffer();
auto blob = otherPool->TakeBlob();
blob->resize(sizeof(data), boost::container::default_init);
std::strcpy(blob->data(), data);
buffer->push_back(std::move(blob));
output.Write(DefaultBufferPool::ConstBuffer{ std::move(buffer) });
}
output.Write(data, sizeof(data));
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == sizeof(data) + 10 + 20 + 2 * sizeof(data));
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 4);
auto blob = buffer.begin();
BOOST_TEST(blob->size() == sizeof(data));
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
++blob;
BOOST_TEST(blob->size() == b1.size());
BOOST_TEST(blob->data() == b1.data());
++blob;
BOOST_TEST(blob->size() == b2.size());
BOOST_TEST(blob->data() == b2.data());
++blob;
BOOST_TEST(blob->size() == 2 * sizeof(data));
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
BOOST_TEST(std::memcmp(blob->data() + sizeof(data), data, sizeof(data)) == 0);
BOOST_TEST((++blob == buffer.end()));
}
BOOST_AUTO_TEST_CASE(WriteBufferRangeTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultBufferPool::ConstBlob constBlob;
DefaultBufferPool::ConstBuffer constBuffer;
const char data[] = "Data!";
{
auto blob = pool->TakeBlob();
blob->resize(sizeof(data), boost::container::default_init);
std::strcpy(blob->data(), data);
constBlob = std::move(blob);
auto buffer = pool->TakeBuffer();
buffer->push_back(constBlob);
buffer->push_back(constBlob);
buffer->push_back(constBlob);
constBuffer = std::move(buffer);
}
constexpr std::size_t leftOffset = 2, rightOffset = 4;
{
DefaultOutputBuffer output{ pool, 4 };
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, std::next(constBuffer.begin()), 0 });
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == constBlob.size() - leftOffset);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
auto blob = buffer.begin();
BOOST_TEST(blob->size() == constBlob.size() - leftOffset);
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
BOOST_TEST((++blob == buffer.end()));
}
{
DefaultOutputBuffer output{ pool, 3 };
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, constBuffer.begin(), rightOffset });
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == rightOffset - leftOffset);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
auto blob = buffer.begin();
BOOST_TEST(blob->size() == rightOffset - leftOffset);
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
BOOST_TEST((++blob == buffer.end()));
}
{
DefaultOutputBuffer output{ pool, 2 };
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, std::next(constBuffer.begin()), rightOffset });
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == constBlob.size() - leftOffset + rightOffset);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 2);
auto blob = buffer.begin();
BOOST_TEST(blob->size() == constBlob.size() - leftOffset);
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
++blob;
BOOST_TEST(blob->size() == rightOffset);
BOOST_TEST(blob->data() == constBlob.data());
BOOST_TEST((++blob == buffer.end()));
}
{
DefaultOutputBuffer output{ pool, 2 };
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, constBuffer.end(), 0 });
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == 3 * constBlob.size() - leftOffset);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 3);
auto blob = buffer.begin();
BOOST_TEST(blob->size() == constBlob.size() - leftOffset);
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
++blob;
BOOST_TEST(blob->size() == constBlob.size());
BOOST_TEST(blob->data() == constBlob.data());
++blob;
BOOST_TEST(blob->size() == constBlob.size());
BOOST_TEST(blob->data() == constBlob.data());
BOOST_TEST((++blob == buffer.end()));
}
}
BOOST_AUTO_TEST_CASE(WriteBondBlobWithPrivateMemoryTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool, 1 };
const char data[] = "Data";
output.Write(static_cast<short>(1));
output.Write(bond::blob{ data, sizeof(data) });
output.Write(static_cast<int>(2));
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == sizeof(data) + sizeof(short) + sizeof(int));
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
BOOST_TEST(buffer.size() == buffer.begin()->size());
auto ptr = buffer.begin()->data();
BOOST_TEST(*reinterpret_cast<const short*>(ptr) == 1);
ptr += sizeof(short);
BOOST_TEST(std::memcmp(ptr, data, sizeof(data)) == 0);
ptr += sizeof(data);
BOOST_TEST(*reinterpret_cast<const int*>(ptr) == 2);
}
BOOST_AUTO_TEST_CASE(WriteBondBlobWithSharedMemoryTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool, 2 };
output.Write(static_cast<short>(1));
const char data[] = "Data";
{
auto blob = pool->TakeBlob();
blob->resize(sizeof(data), boost::container::default_init);
std::strcpy(blob->data(), data);
output.Write(BlobCast(DefaultBufferPool::ConstBlob{ std::move(blob) }, pool->GetMemory()));
}
output.Write(static_cast<int>(2));
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == sizeof(data) + sizeof(short) + sizeof(int));
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 3);
auto blob = buffer.begin();
BOOST_TEST(blob->size() == sizeof(short));
BOOST_TEST(*reinterpret_cast<const short*>(blob->data()) == 1);
++blob;
BOOST_TEST(blob->size() == sizeof(data));
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
++blob;
BOOST_TEST(blob->size() == sizeof(int));
BOOST_TEST(*reinterpret_cast<const int*>(blob->data()) == 2);
BOOST_TEST((++blob == buffer.end()));
}
BOOST_AUTO_TEST_CASE(WriteEmptyDataTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
{
DefaultOutputBuffer output{ pool };
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(!!buffer);
BOOST_TEST(buffer.size() == 0);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 0);
}
DefaultOutputBuffer output{ pool };
output.Write(bond::blob{});
output.Write(DefaultBufferPool::ConstBuffer{});
output.Write(DefaultBufferPool::ConstBuffer::Range{});
{
auto buffer = pool->TakeBuffer();
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
output.Write(constBuffer);
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 });
}
{
auto buffer = pool->TakeBuffer();
buffer->push_back(DefaultBufferPool::ConstBlob{});
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
output.Write(constBuffer);
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 });
}
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(!!buffer);
BOOST_TEST(buffer.size() == 0);
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 0);
}
BOOST_AUTO_TEST_CASE(FlushTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool };
const char data[] = "Data";
const auto& buffer = output.GetBuffer();
output.Write(data, sizeof(data));
BOOST_TEST(buffer->empty());
output.Flush();
BOOST_TEST(buffer->size() == 1);
BOOST_TEST(std::memcmp(buffer->front().data(), data, sizeof(data)) == 0);
output.Write(data, sizeof(data));
BOOST_TEST(buffer->size() == 1);
output.Flush();
BOOST_TEST(buffer->size() == 2);
BOOST_TEST(std::memcmp(buffer->back().data(), data, sizeof(data)) == 0);
}
BOOST_AUTO_TEST_CASE(GetBufferTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool };
const auto& constOutput = output;
BOOST_TEST(output.GetBufferPool() == pool);
const char data[] = "Data";
BOOST_CHECK_NO_THROW(constOutput.GetBuffer());
BOOST_CHECK_NO_THROW(output.GetBuffer());
BOOST_TEST(&output.GetBuffer() == &constOutput.GetBuffer());
BOOST_TEST(output.GetBuffer()->empty());
output.Write(data, sizeof(data));
BOOST_CHECK_THROW(constOutput.GetBuffer(), std::exception);
BOOST_CHECK_NO_THROW(output.GetBuffer());
BOOST_CHECK_NO_THROW(constOutput.GetBuffer());
output.Write(data, sizeof(data));
BOOST_CHECK_THROW(constOutput.GetBuffer(), std::exception);
auto buffer = std::move(output).GetBuffer();
BOOST_TEST(buffer.size() == 2 * sizeof(data));
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 2);
auto blob = buffer.begin();
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
++blob;
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
BOOST_TEST((++blob == buffer.end()));
}
BOOST_AUTO_TEST_CASE(CreateOutputBufferTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
DefaultOutputBuffer output{ pool };
output.Write(1);
{
const auto& buffer = output.GetBuffer();
BOOST_TEST(!!buffer);
BOOST_TEST(buffer->size() == 1);
}
auto output2 = CreateOutputBuffer(output);
{
const auto& buffer = output2.GetBuffer();
BOOST_TEST(!!buffer);
BOOST_TEST(buffer->empty());
}
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,342 @@
#include "stdafx.h"
#include "IPC/Bond/Serializer.h"
#include "IPC/detail/RandomString.h"
#include <bond/core/bond.h>
#include <bond/core/bond_types.h>
#include <bond/core/tuple.h>
#include <bond/protocol/simple_binary.h>
#include <bond/protocol/compact_binary.h>
#include <bond/protocol/fast_binary.h>
#include <bond/protocol/simple_json_reader.h>
#include <bond/protocol/simple_json_writer.h>
#include <string>
#include <vector>
#include <map>
using ValueStruct = std::tuple<
std::int8_t,
std::int16_t,
std::int32_t,
std::int64_t,
std::uint8_t,
std::uint16_t,
std::uint32_t,
std::uint64_t,
bond::blob,
bond::ProtocolType,
bond::blob,
std::string>;
using Struct = std::tuple<
ValueStruct,
std::vector<ValueStruct>,
std::map<bond::ProtocolType, ValueStruct>>;
using BondedStruct = bond::Box<bond::bonded<Struct>>;
namespace bond
{
// TODO: Fix bond to properly work with std::tuple.
inline ValueStruct make_element(std::vector<ValueStruct>& container)
{
return{};
}
inline ValueStruct make_value(std::map<ProtocolType, ValueStruct>& map)
{
return{};
}
} // namespace bond
using namespace IPC::Bond;
using IPC::detail::GenerateRandomString;
using IPC::SharedMemory;
using IPC::create_only;
BOOST_AUTO_TEST_SUITE(SerializerTests)
static_assert(std::is_copy_constructible<DefaultSerializer>::value, "Serializer should be copy constructible.");
static_assert(std::is_copy_assignable<DefaultSerializer>::value, "Serializer should be copy assignable.");
template <typename Function, typename Protocol, typename MakeBondedFunc>
void RunProtocolTest(Function&& func, Protocol protocol, MakeBondedFunc&& makeBondedFunc)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto obj = MakeStruct(*pool);
BondedStruct bondedObj;
bondedObj.value = makeBondedFunc(pool, obj, protocol);
BondedStruct bondedResult;
std::forward<Function>(func)(pool, bondedObj, bondedResult, protocol);
Struct result;
bondedResult.value.Deserialize<DefaultProtocols>(result);
BOOST_TEST((obj == result));
}
template <typename Function, typename Protocol>
void RunProtocolTest(Function&& func, Protocol protocol, std::nullptr_t)
{
RunProtocolTest(
std::forward<Function>(func),
protocol,
[](auto&& /*pool*/, const Struct& obj, auto /*protocol*/)
{
return bond::bonded<Struct>{ obj };
});
}
template <typename Function>
void ForEachRuntimeProtocol(Function&& func, std::initializer_list<bond::ProtocolType> protocols)
{
for (const auto& protocol : protocols)
{
RunProtocolTest(func, protocol, nullptr);
}
}
template <typename Function>
void ForEachRuntimeProtocol(Function&& func)
{
ForEachRuntimeProtocol(
std::forward<Function>(func),
{
bond::ProtocolType::COMPACT_PROTOCOL,
bond::ProtocolType::FAST_PROTOCOL,
bond::ProtocolType::SIMPLE_PROTOCOL,
bond::ProtocolType::SIMPLE_JSON_PROTOCOL
});
}
template <template <typename...> typename R>
struct ProtocolInfo
{
template <typename T>
using Reader = R<T>;
template <typename T>
using Writer = typename bond::get_protocol_writer<R<T>, T>::type;
};
template <template <typename...> typename... Readers, typename Function>
void ForEachReader(Function&& func)
{
std::initializer_list<int>{ ((void)func(ProtocolInfo<Readers>{}), 0)... };
}
template <template <typename...> typename Reader, template <typename...> typename... Readers, typename Function, typename MakeBondedFunc = std::nullptr_t>
void ForEachCompiletimeProtocol(Function&& func, MakeBondedFunc&& makeBondedFunc = nullptr)
{
ForEachReader<Reader, Readers...>(
[func = std::forward<Function>(func), makeBondedFunc = std::forward<MakeBondedFunc>(makeBondedFunc)](auto protocol)
{
RunProtocolTest(func, protocol, makeBondedFunc);
});
}
template <typename Function, typename MakeBondedFunc = std::nullptr_t>
void ForEachCompiletimeProtocol(Function&& func, MakeBondedFunc&& makeBondedFunc = nullptr)
{
ForEachCompiletimeProtocol<
bond::CompactBinaryReader,
bond::SimpleBinaryReader,
bond::FastBinaryReader,
bond::SimpleJsonReader>(std::forward<Function>(func), std::forward<MakeBondedFunc>(makeBondedFunc));
}
Struct MakeStruct(DefaultBufferPool& pool)
{
auto data = "Random data for blob.";
auto blob = pool.TakeBlob();
blob->resize(std::strlen(data) + 1, boost::container::default_init);
std::strcpy(blob->data(), data);
bond::blob bondBlob = BlobCast(DefaultBufferPool::ConstBlob{ std::move(blob) }, pool.GetMemory());
ValueStruct value{
1, 2, 3, 4, 5, 6, 7, 8,
bondBlob,
bond::ProtocolType::COMPACT_PROTOCOL,
{ bondBlob.data(), bondBlob.size() },
data };
return Struct(
value,
{ 10, value },
{
{ bond::ProtocolType::COMPACT_PROTOCOL, value },
{ bond::ProtocolType::SIMPLE_PROTOCOL, value },
{ bond::ProtocolType::SIMPLE_JSON_PROTOCOL, value }
});
}
BOOST_AUTO_TEST_CASE(SerializationUsingRuntimeProtocolTest)
{
ForEachRuntimeProtocol(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, bond::ProtocolType protocol)
{
Deserialize(protocol, Serialize(protocol, pool, bondedObj), bondedResult, pool->GetMemory());
});
ForEachRuntimeProtocol(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, bond::ProtocolType protocol)
{
DefaultSerializer serializer{ protocol, false, pool, pool->GetMemory() };
BOOST_TEST(!serializer.IsMarshaled());
BOOST_TEST(serializer.GetProtocolType() == protocol);
serializer.Deserialize(serializer.Serialize(bondedObj), bondedResult);
});
}
BOOST_AUTO_TEST_CASE(SerializationUsingCompiletimeProtocolTest)
{
ForEachCompiletimeProtocol(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, auto protocol)
{
using Protocol = decltype(protocol);
(void)protocol;
Deserialize<typename Protocol::template Reader>(
Serialize<typename Protocol::template Writer>(pool, bondedObj), bondedResult, pool->GetMemory());
});
}
BOOST_AUTO_TEST_CASE(MarshalingUsingRuntimeProtocolTest)
{
auto protocols =
{
bond::ProtocolType::COMPACT_PROTOCOL,
bond::ProtocolType::FAST_PROTOCOL,
bond::ProtocolType::SIMPLE_PROTOCOL
};
ForEachRuntimeProtocol(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, bond::ProtocolType protocol)
{
Unmarshal(Marshal(protocol, pool, bondedObj), bondedResult, pool->GetMemory());
},
protocols);
ForEachRuntimeProtocol(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, bond::ProtocolType protocol)
{
DefaultSerializer serializer{ protocol, true, pool, pool->GetMemory() };
BOOST_TEST(serializer.IsMarshaled());
BOOST_TEST(serializer.GetProtocolType() == protocol);
serializer.Deserialize(serializer.Serialize(bondedObj), bondedResult);
},
protocols);
}
BOOST_AUTO_TEST_CASE(MarshalingUsingCompiletimeProtocolTest)
{
ForEachCompiletimeProtocol<
bond::CompactBinaryReader,
bond::SimpleBinaryReader,
bond::FastBinaryReader>(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, auto protocol)
{
using Protocol = decltype(protocol);
(void)protocol;
Unmarshal(Marshal<typename Protocol::template Writer>(pool, bondedObj), bondedResult, pool->GetMemory());
});
}
BOOST_AUTO_TEST_CASE(TranscodingTest)
{
ForEachCompiletimeProtocol<
bond::CompactBinaryReader,
bond::SimpleBinaryReader,
bond::FastBinaryReader>(
[&](auto&& pool, BondedStruct& bondedObj, BondedStruct& bondedResult, auto protocol)
{
using Protocol = decltype(protocol);
(void)protocol;
Deserialize<typename Protocol::template Reader>(
Serialize<typename Protocol::template Writer>(pool, bondedObj), bondedResult, pool->GetMemory());
},
[](auto&& pool, const Struct& obj, auto protocol)
{
using Protocol = decltype(protocol);
(void)protocol;
return bond::bonded<Struct>{
typename Protocol::template Reader<DefaultInputBuffer>{
DefaultInputBuffer{ Serialize<typename Protocol::template Writer>(pool, obj), pool->GetMemory() } } };
});
}
BOOST_AUTO_TEST_CASE(FailedDeserializationTest)
{
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
auto obj = MakeStruct(*pool);
DefaultSerializer serializer{ bond::ProtocolType::COMPACT_PROTOCOL, false, pool, pool->GetMemory() };
auto buffer = serializer.Serialize(obj);
BOOST_TEST((serializer.Deserialize<Struct>(buffer).get() == obj));
DefaultSerializer wrongSerializer{ serializer.GetProtocolType(), !serializer.IsMarshaled(), pool, pool->GetMemory() };
BOOST_CHECK_THROW(wrongSerializer.Deserialize<Struct>(buffer).get(), std::exception);
}
BOOST_AUTO_TEST_CASE(MemoryOwnershipTest)
{
auto memory = std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024);
auto data = "Blob content";
bond::Box<bond::blob> obj;
obj.value = { data, static_cast<std::uint32_t>(std::strlen(data)) + 1 };
BOOST_TEST(memory.unique());
decltype(obj) serializedObj, marshaledObj;
{
auto pool = std::make_shared<DefaultBufferPool>(memory);
{
DefaultSerializer serializer{ bond::ProtocolType::COMPACT_PROTOCOL, false, pool, memory };
BOOST_TEST(serializer.GetOutputBufferPool() == pool);
BOOST_TEST(serializer.GetInputMemory() == memory);
serializer.Deserialize(serializer.Serialize(obj), serializedObj);
}
{
DefaultSerializer serializer{ bond::ProtocolType::COMPACT_PROTOCOL, true, pool, memory };
BOOST_TEST(serializer.GetOutputBufferPool() == pool);
BOOST_TEST(serializer.GetInputMemory() == memory);
serializer.Deserialize(serializer.Serialize(obj), marshaledObj);
}
}
BOOST_TEST(memory.use_count() == 3);
BOOST_TEST((obj == serializedObj));
BOOST_TEST(memory->Contains(serializedObj.value.content()));
BOOST_TEST(memory->Contains(serializedObj.value.content() + serializedObj.value.size() - 1));
serializedObj.value = {};
BOOST_TEST(memory.use_count() == 2);
BOOST_TEST((obj == marshaledObj));
BOOST_TEST(memory->Contains(marshaledObj.value.content()));
BOOST_TEST(memory->Contains(marshaledObj.value.content() + marshaledObj.value.size() - 1));
marshaledObj.value = {};
BOOST_TEST(memory.unique());
}
BOOST_AUTO_TEST_SUITE_END()

Просмотреть файл

@ -0,0 +1,397 @@
#include "stdafx.h"
#include "IPC/Bond/Transport.h"
#include "IPC/detail/RandomString.h"
#include <cmath>
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
#include <mutex>
#include <condition_variable>
#include <future>
#include <bond/core/bond_types.h>
#include <bond/protocol/simple_json_writer.h>
BOOST_AUTO_TEST_SUITE(TransportTests)
struct Traits : IPC::Bond::DefaultTraits
{
using TimeoutFactory = IPC::Policies::NullTimeoutFactory; // Using no-timeout to make these tests reliable.
template <typename Context>
using TransactionManager = IPC::Policies::TransactionManager<Context, TimeoutFactory>;
};
BOOST_AUTO_TEST_CASE(AcceptorConnectorTest)
{
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(y);
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto closeHandler = []
{
std::clog << "Connection is closed." << std::endl;
};
using Transport = IPC::Bond::Transport<bond::Box<int>, bond::Box<double>, Traits>;
Transport transport;
auto name = IPC::detail::GenerateRandomString();
std::mutex lock;
std::condition_variable serverInserted;
std::vector<std::unique_ptr<Transport::Server>> servers;
auto acceptor = transport.MakeServerAcceptor(
name.c_str(),
[&](auto futureConnection)
{
try
{
std::lock_guard<std::mutex> guard{ lock };
servers.push_back(transport.MakeServer(futureConnection.get(), [&](auto&&...) { return serverHandler; }, closeHandler));
serverInserted.notify_one();
}
catch (const std::exception& e)
{
std::clog << "Failed to accept a server: " << e.what() << std::endl;
}
});
std::unique_ptr<Transport::Client> client;
auto connector = transport.MakeClientConnector();
try
{
client = transport.MakeClient(connector.Connect(name.c_str()).get(), closeHandler);
}
catch (const std::exception& e)
{
std::clog << "Failed to connect a client: " << e.what() << std::endl;
}
BOOST_TEST_REQUIRE(!!client);
{
std::unique_lock<std::mutex> guard{ lock };
serverInserted.wait(guard, [&] { return !servers.empty(); });
}
BOOST_TEST(servers.size() == 1);
bond::Box<int> x;
x.value = 111;
bond::Box<double> y;
try
{
y = (*client)(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(ReverseConnectionAcceptorConnectorTest)
{
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(std::move(y));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto closeHandler = []
{
std::clog << "Connection is closed." << std::endl;
};
using Transport = IPC::Bond::Transport<bond::Box<int>, bond::Box<double>, Traits>;
Transport transport;
auto name = IPC::detail::GenerateRandomString();
std::mutex lock;
std::condition_variable clientInserted;
std::vector<std::unique_ptr<Transport::Client>> clients;
auto acceptor = transport.MakeClientAcceptor(
name.c_str(),
[&](auto futureConnection)
{
try
{
std::lock_guard<std::mutex> guard{ lock };
clients.push_back(transport.MakeClient(futureConnection.get(), closeHandler));
clientInserted.notify_one();
}
catch (const std::exception& e)
{
std::clog << "Failed to accept a client: " << e.what() << std::endl;
}
});
std::unique_ptr<Transport::Server> server;
auto connector = transport.MakeServerConnector();
try
{
server = transport.MakeServer(connector.Connect(name.c_str()).get(), [&](auto&&...) { return serverHandler; }, closeHandler);
}
catch (const std::exception& e)
{
std::clog << "Failed to connect a server: " << e.what() << std::endl;
}
BOOST_TEST_REQUIRE(!!server);
{
std::unique_lock<std::mutex> guard{ lock };
clientInserted.wait(guard, [&] { return !clients.empty(); });
}
BOOST_TEST(clients.size() == 1);
bond::Box<int> x;
x.value = 222;
bond::Box<double> y;
try
{
y = (*clients.front())(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(AcceptConnectTest)
{
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(std::move(y));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
using Transport = IPC::Bond::Transport<bond::Box<int>, bond::Box<double>, Traits>;
Transport transport;
auto name = IPC::detail::GenerateRandomString();
auto serversAccessor = transport.AcceptServers(name.c_str(), [&](auto&&...) { return serverHandler; });
auto clientAccessor = transport.ConnectClient(name.c_str(), false);
std::shared_ptr<Transport::Client> client;
try
{
client = clientAccessor();
}
catch (const std::exception& e)
{
std::clog << "Client is not available: " << e.what() << std::endl;
}
BOOST_TEST_REQUIRE(!!client);
bond::Box<int> x;
x.value = 333;
bond::Box<double> y;
try
{
y = (*client)(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(ReverseConnectionAcceptConnectTest)
{
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(std::move(y));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
using Transport = IPC::Bond::Transport<bond::Box<int>, bond::Box<double>, Traits>;
Transport transport;
auto name = IPC::detail::GenerateRandomString();
auto clientsAccessor = transport.AcceptClients(name.c_str());
auto serverAccessor = transport.ConnectServer(name.c_str(), [&](auto&&...) { return serverHandler; }, false);
std::shared_ptr<Transport::Server> server;
try
{
server = serverAccessor();
}
catch (const std::exception& e)
{
std::clog << "Server is not available: " << e.what() << std::endl;
}
BOOST_TEST_REQUIRE(!!server);
bond::Box<int> x;
x.value = 444;
bond::Box<double> y;
try
{
y = (*clientsAccessor()->front())(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(DynamicDataTest)
{
using Struct = bond::Box<bond::blob>;
auto serverHandler = [](IPC::Bond::DefaultBufferPool& pool, std::future<Struct> futureRequest, auto&& callback)
{
try
{
auto request = futureRequest.get();
auto blob = pool.TakeBlob();
blob->resize(2 * request.value.size(), boost::container::default_init);
std::memcpy(blob->data(), request.value.data(), request.value.size());
std::memcpy(blob->data() + request.value.size(), request.value.data(), request.value.size());
Struct response;
response.value = IPC::Bond::BlobCast(IPC::Bond::DefaultBufferPool::ConstBlob{ std::move(blob) }, pool.GetMemory());
callback(std::move(response));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
using Transport = IPC::Bond::Transport<Struct, Struct, Traits>;
Transport transport;
auto name = IPC::detail::GenerateRandomString();
auto serversAccessor = transport.AcceptServers(
name.c_str(),
[&](const auto& /*connection*/, const auto& pools, const auto& /*serializer*/)
{
return [&serverHandler, pool = pools.GetOutputPool()](std::future<Struct> request, auto&& callback)
{
return serverHandler(*pool, std::move(request), std::forward<decltype(callback)>(callback));
};
});
auto clientAccessor = transport.ConnectClient(name.c_str(), false);
std::shared_ptr<Transport::Client> client;
try
{
client = clientAccessor();
}
catch (const std::exception& e)
{
std::clog << "Client is not available: " << e.what() << std::endl;
}
BOOST_TEST_REQUIRE(!!client);
const char str[] = "Hello World";
Struct result;
try
{
auto pool = client->GetOutputPool();
auto blob = pool->TakeBlob();
blob->resize(sizeof(str), boost::container::default_init);
std::strcpy(blob->data(), str);
Struct request;
request.value = IPC::Bond::BlobCast(IPC::Bond::DefaultBufferPool::ConstBlob{ std::move(blob) }, pool->GetMemory());
result = (*client)(std::move(request)).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(result.value.size() == 2 * sizeof(str));
BOOST_TEST(std::strcmp(result.value.content(), str) == 0);
BOOST_TEST(std::strcmp(result.value.content() + sizeof(str), str) == 0);
}
BOOST_AUTO_TEST_SUITE_END()

403
UnitTests/UsageTests.cpp Normal file
Просмотреть файл

@ -0,0 +1,403 @@
#include "stdafx.h"
#include "IPC/Bond/Accept.h"
#include "IPC/Bond/Acceptor.h"
#include "IPC/Bond/Connect.h"
#include "IPC/Bond/Connector.h"
#include "IPC/detail/RandomString.h"
#include <cmath>
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
#include <mutex>
#include <condition_variable>
#include <future>
#include <bond/core/bond_types.h>
#include <bond/protocol/simple_json_writer.h>
BOOST_AUTO_TEST_SUITE(UsageTests)
struct Traits : IPC::Bond::DefaultTraits
{
using TimeoutFactory = IPC::Policies::NullTimeoutFactory; // Using no-timeout to make these tests reliable.
template <typename Context>
using TransactionManager = IPC::Policies::TransactionManager<Context, TimeoutFactory>;
};
BOOST_AUTO_TEST_CASE(AcceptorConnectorTest)
{
constexpr auto protocol = bond::ProtocolType::COMPACT_PROTOCOL;
constexpr auto marshal = false;
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(y);
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto closeHandler = []
{
std::clog << "Connection is closed." << std::endl;
};
auto name = IPC::detail::GenerateRandomString();
std::mutex lock;
std::condition_variable serverInserted;
std::vector<std::unique_ptr<IPC::Bond::Server<bond::Box<int>, bond::Box<double>, Traits>>> servers;
IPC::Bond::ServerAcceptor<bond::Box<int>, bond::Box<double>, Traits> acceptor{
name.c_str(),
[&](auto futureConnection)
{
try
{
std::lock_guard<std::mutex> guard{ lock };
servers.push_back(IPC::Bond::MakeServer<bond::Box<int>, bond::Box<double>, Traits>(
futureConnection.get(),
[&](auto&&...) { return serverHandler; },
closeHandler,
protocol,
marshal));
serverInserted.notify_one();
}
catch (const std::exception& e)
{
std::clog << "Failed to accept a server: " << e.what() << std::endl;
}
} };
std::unique_ptr<IPC::Bond::Client<bond::Box<int>, bond::Box<double>, Traits>> client;
IPC::Bond::ClientConnector<bond::Box<int>, bond::Box<double>, Traits> connector;
try
{
client = IPC::Bond::MakeClient<bond::Box<int>, bond::Box<double>, Traits>(
connector.Connect(name.c_str()).get(), closeHandler, protocol, marshal);
}
catch (const std::exception& e)
{
std::clog << "Failed to connect a client: " << e.what() << std::endl;
}
{
std::unique_lock<std::mutex> guard{ lock };
serverInserted.wait(guard, [&] { return !servers.empty(); });
}
BOOST_TEST(servers.size() == 1);
bond::Box<int> x;
x.value = 111;
bond::Box<double> y;
try
{
y = (*client)(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(ReverseConnectionAcceptorConnectorTest)
{
constexpr auto protocol = bond::ProtocolType::COMPACT_PROTOCOL;
constexpr auto marshal = false;
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(std::move(y));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto closeHandler = []
{
std::clog << "Connection is closed." << std::endl;
};
auto name = IPC::detail::GenerateRandomString();
std::mutex lock;
std::condition_variable clientInserted;
std::vector<std::unique_ptr<IPC::Bond::Client<bond::Box<int>, bond::Box<double>, Traits>>> clients;
IPC::Bond::ClientAcceptor<bond::Box<int>, bond::Box<double>, Traits> acceptor{
name.c_str(),
[&](auto futureConnection)
{
try
{
std::lock_guard<std::mutex> guard{ lock };
clients.push_back(IPC::Bond::MakeClient<bond::Box<int>, bond::Box<double>, Traits>(
futureConnection.get(), closeHandler, protocol, marshal));
clientInserted.notify_one();
}
catch (const std::exception& e)
{
std::clog << "Failed to accept a client: " << e.what() << std::endl;
}
} };
std::unique_ptr<IPC::Bond::Server<bond::Box<int>, bond::Box<double>, Traits>> server;
IPC::Bond::ServerConnector<bond::Box<int>, bond::Box<double>, Traits> connector;
try
{
server = IPC::Bond::MakeServer<bond::Box<int>, bond::Box<double>, Traits>(
connector.Connect(name.c_str()).get(),
[&](auto&&...) { return serverHandler; },
closeHandler,
protocol,
marshal);
}
catch (const std::exception& e)
{
std::clog << "Failed to connect a server: " << e.what() << std::endl;
}
{
std::unique_lock<std::mutex> guard{ lock };
clientInserted.wait(guard, [&] { return !clients.empty(); });
}
BOOST_TEST(clients.size() == 1);
bond::Box<int> x;
x.value = 222;
bond::Box<double> y;
try
{
y = (*clients.front())(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(AcceptConnectTest)
{
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(std::move(y));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto name = IPC::detail::GenerateRandomString();
auto serversAccessor = IPC::Bond::AcceptServers<bond::Box<int>, bond::Box<double>, Traits>(
name.c_str(), [&](auto&&...) { return serverHandler; });
auto clientAccessor = IPC::Bond::ConnectClient(
name.c_str(), std::make_shared<IPC::Bond::ClientConnector<bond::Box<int>, bond::Box<double>, Traits>>(), false);
std::shared_ptr<IPC::Bond::Client<bond::Box<int>, bond::Box<double>, Traits>> client;
try
{
client = clientAccessor();
}
catch (const std::exception& e)
{
std::clog << "Client is not available: " << e.what() << std::endl;
}
assert(client);
bond::Box<int> x;
x.value = 333;
bond::Box<double> y;
try
{
y = (*client)(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(ReverseConnectionAcceptConnectTest)
{
auto serverHandler = [](std::future<bond::Box<int>> x, auto&& callback)
{
try
{
bond::Box<double> y;
y.value = std::sqrt(x.get().value);
callback(std::move(y));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto name = IPC::detail::GenerateRandomString();
auto clientsAccessor = IPC::Bond::AcceptClients<bond::Box<int>, bond::Box<double>, Traits>(name.c_str());
auto serverAccessor = IPC::Bond::ConnectServer(
name.c_str(),
std::make_shared<IPC::Bond::ServerConnector<bond::Box<int>, bond::Box<double>, Traits>>(),
[&](auto&&...) { return serverHandler; },
false);
std::shared_ptr<IPC::Bond::Server<bond::Box<int>, bond::Box<double>, Traits>> server;
try
{
server = serverAccessor();
}
catch (const std::exception& e)
{
std::clog << "Server is not available: " << e.what() << std::endl;
}
assert(server);
bond::Box<int> x;
x.value = 444;
bond::Box<double> y;
try
{
y = (*clientsAccessor()->front())(x).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(y.value == std::sqrt(x.value), boost::test_tools::tolerance(0.0001));
}
BOOST_AUTO_TEST_CASE(DynamicDataTest)
{
using Struct = bond::Box<bond::blob>;
auto serverHandler = [](IPC::Bond::DefaultBufferPool& pool, std::future<Struct> futureRequest, auto&& callback)
{
try
{
auto request = futureRequest.get();
auto blob = pool.TakeBlob();
blob->resize(2 * request.value.size(), boost::container::default_init);
std::memcpy(blob->data(), request.value.data(), request.value.size());
std::memcpy(blob->data() + request.value.size(), request.value.data(), request.value.size());
Struct response;
response.value = IPC::Bond::BlobCast(IPC::Bond::DefaultBufferPool::ConstBlob{ std::move(blob) }, pool.GetMemory());
callback(std::move(response));
}
catch (const std::exception& e)
{
std::clog << "Failed to send response: " << e.what() << std::endl;
}
};
auto name = IPC::detail::GenerateRandomString();
auto serversAccessor = IPC::Bond::AcceptServers<Struct, Struct, Traits>(
name.c_str(),
[&](const auto& /*connection*/, const auto& pools, const auto& /*serializer*/)
{
return [&serverHandler, pool = pools.GetOutputPool()](std::future<Struct> request, auto&& callback)
{
return serverHandler(*pool, std::move(request), std::forward<decltype(callback)>(callback));
};
});
auto clientAccessor = IPC::Bond::ConnectClient(
name.c_str(),
std::make_shared<IPC::Bond::ClientConnector<Struct, Struct, Traits>>(),
false);
std::shared_ptr<IPC::Bond::Client<Struct, Struct, Traits>> client;
try
{
client = clientAccessor();
}
catch (const std::exception& e)
{
std::clog << "Client is not available: " << e.what() << std::endl;
}
assert(client);
const char str[] = "Hello World";
Struct result;
try
{
auto pool = client->GetOutputPool();
auto blob = pool->TakeBlob();
blob->resize(sizeof(str), boost::container::default_init);
std::strcpy(blob->data(), str);
Struct request;
request.value = IPC::Bond::BlobCast(IPC::Bond::DefaultBufferPool::ConstBlob{ std::move(blob) }, pool->GetMemory());
result = (*client)(std::move(request)).get();
}
catch (const std::exception& e)
{
std::clog << "Failed to invoke a client: " << e.what() << std::endl;
}
BOOST_TEST(result.value.size() == 2 * sizeof(str));
BOOST_TEST(std::strcmp(result.value.content(), str) == 0);
BOOST_TEST(std::strcmp(result.value.content() + sizeof(str), str) == 0);
}
BOOST_AUTO_TEST_SUITE_END()

1
UnitTests/stdafx.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "stdafx.h"

6
UnitTests/stdafx.h Normal file
Просмотреть файл

@ -0,0 +1,6 @@
#pragma once
#include <Windows.h>
#define BOOST_TEST_MODULE IPC_Bond_UnitTests
#include <boost/test/unit_test.hpp>

Просмотреть файл

@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using NUnit.Framework.Internal;
namespace IPC.Bond.Managed.UnitTests
{
using SharedMemory = IPC.Managed.SharedMemory;
[TestFixture(Category = "ManagedTests")]
public class SerializationTests
{
private readonly Randomizer _rand = new Randomizer();
private byte[] MakeRandomBytes()
{
var buffer = new byte[_rand.Next(1, 1024)];
_rand.NextBytes(buffer);
return buffer;
}
private ValueStruct MakeRandomValueStruct()
{
return new ValueStruct
{
FieldBool = _rand.Next() % 2 == 0,
FieldInt8 = (sbyte)_rand.Next(sbyte.MinValue, sbyte.MaxValue),
FieldUInt8 = (byte)_rand.Next(byte.MinValue, byte.MaxValue),
FieldInt16 = (short)_rand.Next(short.MinValue, short.MaxValue),
FieldUInt16 = (ushort)_rand.Next(ushort.MinValue, ushort.MaxValue),
FieldInt32 = _rand.Next(),
FieldUInt32 = (uint)_rand.NextDouble(),
FieldInt64 = (long)_rand.NextDouble(),
FieldUInt64 = (ulong)_rand.NextDouble(),
FieldFloat = (float)_rand.NextDouble(),
FieldDouble = _rand.NextDouble(),
FieldEnum = (TestEnum)Enum.GetValues(typeof(TestEnum)).GetValue(_rand.Next() % Enum.GetValues(typeof(TestEnum)).Length),
FieldString = System.Text.Encoding.ASCII.GetString(MakeRandomBytes()),
FieldWString = System.Text.Encoding.Unicode.GetString(MakeRandomBytes()),
FieldBlob = new ArraySegment<byte>(MakeRandomBytes())
};
}
private IEnumerable<ValueStruct> MakeRandomValueStructs()
{
var count = _rand.Next(0, _rand.Next(0, 100));
for (int i = 0; i < count; ++i)
{
yield return MakeRandomValueStruct();
}
}
private Dictionary<string, ValueStruct> MakeRandomValueStructMap()
{
var map = new Dictionary<string, ValueStruct>();
var count = _rand.Next(0, _rand.Next(0, 100));
for (int i = 0; i < count; ++i)
{
map[Guid.NewGuid().ToString()] = MakeRandomValueStruct();
}
return map;
}
private TestStruct MakeRandomStruct()
{
return new TestStruct
{
FieldList = new LinkedList<ValueStruct>(MakeRandomValueStructs()),
FieldVector = new List<ValueStruct>(MakeRandomValueStructs()),
FieldSet = new HashSet<int>(Enumerable.Repeat(_rand.Next(), 100)),
FieldMap = new Dictionary<string, ValueStruct>(MakeRandomValueStructMap()),
FieldNullable = _rand.Next() % 2 == 0 ? MakeRandomValueStruct() : null,
FieldBonded = new global::Bond.Bonded<ValueStruct>(MakeRandomValueStruct())
};
}
[Test]
public void SerializerTest()
{
using (var memory = SharedMemory.Create(Guid.NewGuid().ToString(), 4 * 1024 * 1024))
using (var pool = new BufferPool(memory))
{
foreach (var protocol in new global::Bond.ProtocolType[] { global::Bond.ProtocolType.COMPACT_PROTOCOL, global::Bond.ProtocolType.FAST_PROTOCOL, global::Bond.ProtocolType.SIMPLE_PROTOCOL })
{
foreach (var marshal in new bool[] { true, false })
{
var serializer = new Serializer(protocol, marshal, pool, memory);
Assert.AreEqual(protocol, serializer.ProtocolType);
Assert.AreEqual(marshal, serializer.IsMarshaled);
var s1 = MakeRandomStruct();
TestStruct s2;
using (var buffer = serializer.Serialize(s1))
{
s2 = serializer.Deserialize<TestStruct>(buffer);
}
// Bond.Comparer.Equal does not properly work with Bonded<T> fields.
Assert.IsTrue(global::Bond.Comparer.Equal(s1.FieldBonded.Deserialize(), s2.FieldBonded.Deserialize()));
s1.FieldBonded = s2.FieldBonded = global::Bond.Bonded<ValueStruct>.Empty;
Assert.IsTrue(global::Bond.Comparer.Equal(s1, s2));
}
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
namespace IPC.Bond.Managed.UnitTests
enum TestEnum
{
Value1 = -1,
Value2 = 0,
Value3 = 1
}
struct ValueStruct
{
01: bool FieldBool;
02: int8 FieldInt8;
03: uint8 FieldUInt8;
04: int16 FieldInt16;
05: uint16 FieldUInt16;
06: int32 FieldInt32;
07: uint32 FieldUInt32;
08: int64 FieldInt64;
09: uint64 FieldUInt64;
10: float FieldFloat;
11: double FieldDouble;
12: string FieldString;
13: wstring FieldWString;
14: TestEnum FieldEnum = Value1;
15: blob FieldBlob;
};
struct TestStruct
{
1: list<ValueStruct> FieldList;
2: vector<ValueStruct> FieldVector;
3: set<int32> FieldSet;
4: map<string, ValueStruct> FieldMap;
5: nullable<ValueStruct> FieldNullable;
6: bonded<ValueStruct> FieldBonded;
}

Просмотреть файл

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using NUnit.Framework;
namespace IPC.Bond.Managed.UnitTests
{
[TestFixture(Category = "ManagedTests")]
public class TransportTests
{
[Test]
public async Task AcceptorConnectorTest()
{
var address = Guid.NewGuid().ToString();
bool isClientClosed = false;
bool isServerClosed = false;
var config = new Config { DefaultRequestTimeout = System.Threading.Timeout.InfiniteTimeSpan };
using (var transport = new Transport<global::Bond.Box<int>, global::Bond.Box<int>>(config))
using (var acceptor = transport.MakeServerAcceptor(address, (inMemory, outMemory) => x => Task.FromResult(x)))
using (var connector = transport.MakeClientConnector())
{
var servers = new List<Transport<global::Bond.Box<int>, global::Bond.Box<int>>.Server>();
var newServerEvent = new System.Threading.ManualResetEventSlim(false);
acceptor.Accepted += (sender, args) =>
{
lock (servers)
{
servers.Add(args.Component);
}
newServerEvent.Set();
};
Transport<global::Bond.Box<int>, global::Bond.Box<int>>.Server server;
using (var client = await connector.ConnectAsync(address))
{
newServerEvent.Wait();
lock (servers)
{
Assert.AreEqual(1, servers.Count);
server = servers.First();
}
Assert.IsFalse(server.IsClosed);
server.Closed += (sender, args) => { isServerClosed = true; };
Assert.IsFalse(client.IsClosed);
client.Closed += (sender, args) => { isClientClosed = true; };
var request = new global::Bond.Box<int> { value = 100 };
var response = await client.InvokeAsync(request);
Assert.IsTrue(global::Bond.Comparer.Equal(request, response));
}
server.Dispose();
}
Assert.IsTrue(isClientClosed);
Assert.IsTrue(isServerClosed);
}
[Test]
public async Task AcceptConnectTest()
{
var address = Guid.NewGuid().ToString();
var config = new Config { DefaultRequestTimeout = System.Threading.Timeout.InfiniteTimeSpan };
using (var transport = new Transport<global::Bond.Box<int>, global::Bond.Box<int>>(config))
using (var serversAccessor = transport.AcceptServers(address, (inMemory, outMemory) => x => Task.FromResult(x)))
using (var clientAccessor = transport.ConnectClient(address, false))
{
var request = new global::Bond.Box<int> { value = 200 };
var response = await clientAccessor.Client.InvokeAsync(request);
Assert.IsTrue(global::Bond.Comparer.Equal(request, response));
}
}
}
}

Просмотреть файл

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{BDFCB3AD-21A8-446E-840B-68718C49E7D4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>IPC.Bond.Managed.UnitTests</RootNamespace>
<AssemblyName>IPC.Bond.Managed.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<AssemblyClsCompliant>false</AssemblyClsCompliant>
<PlatformTarget>x64</PlatformTarget>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<OutputPath>..\x64\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>..\x64\Release\</OutputPath>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="Bond">
<HintPath>..\IPC\Packages\Bond.Core.CSharp.6.0.0\lib\net45\Bond.dll</HintPath>
</Reference>
<Reference Include="Bond.Attributes">
<HintPath>..\IPC\Packages\Bond.Core.CSharp.6.0.0\lib\net45\Bond.Attributes.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\IPC\Packages\NUnit.3.6.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed">
<HintPath>..\IPC\$(Platform)\$(Configuration)\IPC.Managed.dll</HintPath>
</Reference>
<Reference Include="IPC.Managed.Transport">
<HintPath>..\IPC\$(Platform)\$(Configuration)\IPC.Managed.Transport.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Managed\Build\Managed.vcxproj">
<Project>{705098F7-AAAA-4954-8165-FDDCD66231F0}</Project>
<Name>Managed</Name>
</ProjectReference>
<ProjectReference Include="..\Transport\Transport.csproj">
<Project>{BDAAAAAD-21a8-446e-840b-68718c49e7d4}</Project>
<Name>Transport</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="SerializationTests.cs" />
<Compile Include="TransportTests.cs" />
<Compile Include="generated\Test_types.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Test.bond" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>$(SolutionDir)\IPC\packages\Bond.Compiler.6.0.0\tools\gbc.exe c# -o=$(MSBuildProjectDirectory)\generated $(MSBuildProjectDirectory)\Test.bond</PreBuildEvent>
</PropertyGroup>
</Project>

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Bond.Compiler" version="6.0.0" targetFramework="net46" />
<package id="Bond.Core.CSharp" version="6.0.0" targetFramework="net46" />
<package id="NUnit" version="3.6.1" targetFramework="net46" />
</packages>

1
bond Submodule

@ -0,0 +1 @@
Subproject commit 0236301fe809802ecd754d5d047288ef397f9c79

18
bond.cmd Normal file
Просмотреть файл

@ -0,0 +1,18 @@
@setlocal
@set PreferredToolArchitecture=x64
@set BOOST_ROOT=%CD%\IPC\packages\boost.1.63.0.0\lib\native\include
@set BOOST_LIBRARYDIR=%CD%\IPC\packages\boost.1.63.0.0
@set BOND_GBC_PATH=%CD%\IPC\packages\Bond.Compiler.6.0.0\tools
@mkdir bond\build
@mkdir bond\build\target
@pushd bond\build
@cmake -G "Visual Studio 14 2015 Win64" -DBOND_LIBRARIES_ONLY=ON -DBOND_ENABLE_COMM=FALSE -DBOND_ENABLE_GRPC=FALSE -DCMAKE_INSTALL_PREFIX=%CD%\target ..
@cmake --build . --target
@cmake --build . --target INSTALL
@popd
@endlocal

6
nuget.config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="IPC\Packages" />
</config>
</configuration>