├── README.md ├── src ├── ndv2lib │ ├── ReadMe.txt │ ├── ndv2lib.vcxproj.filters │ ├── ndsupport.h │ ├── ndspi_ext_mlx.h │ ├── ndv2lib.vcxproj │ ├── nddef.h │ ├── ndstatus.h │ ├── ndv2helper.cpp │ ├── ndioctl.h │ └── ndspi.h ├── hermes │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── FMem.hpp │ ├── hermes.vcxproj.filters │ ├── Utilities.hpp │ ├── NDUtils.cpp │ ├── internal.hpp │ ├── UtilitiesWin.cpp │ ├── hermes.vcxproj │ ├── hermes.hpp │ ├── FixMem.cpp │ └── HermesFixedRIO.hpp ├── Pingpong │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── Pingpong.vcxproj.filters │ ├── ReadMe.txt │ ├── Pingpong.vcxproj │ └── Pingpong.cpp ├── UnitTest │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── UnitTest.vcxproj.filters │ ├── UtilTest.cpp │ └── UnitTest.vcxproj └── hermes.sln ├── .gitignore ├── GetDependencies.bat └── SECURITY.md /README.md: -------------------------------------------------------------------------------- 1 | # hermes 2 | Code example for NDv2, Microsoft's RDMA interface 3 | 4 | This project implements a messaging library with async send and receive APIs. 5 | 6 | -------------------------------------------------------------------------------- /src/ndv2lib/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | STATIC LIBRARY : ndv2lib 3 | ======================================================================== 4 | 5 | NDv2 library from Microsoft -------------------------------------------------------------------------------- /src/hermes/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // hermes.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /src/Pingpong/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // Pingpong.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /src/UnitTest/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // UnitTest.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /src/Pingpong/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /src/UnitTest/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /src/hermes/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /src/Pingpong/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /src/UnitTest/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | // Headers for CppUnitTest 11 | #include "CppUnitTest.h" 12 | 13 | // TODO: reference additional headers your program requires here 14 | -------------------------------------------------------------------------------- /src/hermes/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | 12 | 13 | 14 | // TODO: reference additional headers your program requires here 15 | -------------------------------------------------------------------------------- /src/hermes/FMem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "Mem.hpp" 6 | 7 | 8 | namespace mbuf 9 | { 10 | 11 | class BufManager 12 | { 13 | public: 14 | virtual DisposableBuffer* Allocate( 15 | uint32_t size, 16 | uint32_t alignment = 8, 17 | uint32_t offset = 0) = 0; 18 | }; 19 | 20 | extern std::unique_ptr FixedBufManagerFactory(); 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | [Bb]in 6 | obj 7 | objd 8 | out/ 9 | tmp/ 10 | x64/ 11 | ipch/ 12 | extern/ 13 | App_Data 14 | *.user 15 | *.sln.cache 16 | *.userosscache 17 | *.suo 18 | TestResults 19 | [Tt]humbs.db 20 | *.VC.db 21 | *.VC.opendb 22 | *.nupkg 23 | -------------------------------------------------------------------------------- /GetDependencies.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM very naive dependency management, need a better one. 4 | 5 | pushd "%~dp0" 6 | 7 | IF EXIST ".\extern" GOTO HAS_EXTERN 8 | 9 | mkdir extern 10 | 11 | :HAS_EXTERN 12 | 13 | cd extern 14 | 15 | IF EXIST ".\GSL" GOTO GSL_PULLED 16 | 17 | echo "pulling GSL..." 18 | 19 | git clone --depth=1 https://github.com/Microsoft/GSL.git 20 | 21 | :GSL_PULLED 22 | 23 | 24 | IF EXIST ".\mala" GOTO MALA_PULLED 25 | 26 | echo "pulling mala..." 27 | 28 | git clone --depth=1 https://github.com/Microsoft/mala.git 29 | 30 | :MALA_PULLED 31 | 32 | 33 | :END 34 | popd -------------------------------------------------------------------------------- /src/UnitTest/UnitTest.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Pingpong/Pingpong.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/ndv2lib/ndv2lib.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/Pingpong/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : Pingpong Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this Pingpong application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your Pingpong application. 9 | 10 | 11 | Pingpong.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | Pingpong.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | Pingpong.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named Pingpong.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /src/UnitTest/UtilTest.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Utilities.hpp" 9 | 10 | 11 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 12 | 13 | namespace UnitTest 14 | { 15 | const size_t BUF_SIZE = 1030; 16 | TEST_CLASS(UtilTest) 17 | { 18 | public: 19 | 20 | TEST_METHOD(CRCTest) 21 | { 22 | auto testBuf = reinterpret_cast(_aligned_malloc(BUF_SIZE * sizeof(uint64_t), 16)); 23 | auto dstBuf = reinterpret_cast(_aligned_malloc(BUF_SIZE * sizeof(uint64_t), 16)); 24 | 25 | auto tv = gsl::span(reinterpret_cast(testBuf), BUF_SIZE * sizeof(uint64_t)); 26 | auto dv = gsl::span(reinterpret_cast(dstBuf), BUF_SIZE * sizeof(uint64_t)); 27 | 28 | std::default_random_engine generator; 29 | std::uniform_int_distribution distribution; 30 | 31 | for (int i = 0; i < BUF_SIZE; i++) 32 | { 33 | testBuf[i] = distribution(generator); 34 | } 35 | 36 | auto leftcrc = uint32_t(0); 37 | auto rightcrc = uint32_t(0); 38 | 39 | Utilities::ComputeCRC(tv, leftcrc, rightcrc); 40 | 41 | auto l = uint32_t(0); 42 | auto r = uint32_t(0); 43 | Utilities::ComputeCRC(dv, tv, l, r); 44 | 45 | Audit::Assert(leftcrc == l); 46 | Audit::Assert(rightcrc == r); 47 | 48 | for (int i = 0; i < BUF_SIZE; i++) 49 | { 50 | Audit::Assert(testBuf[i] == dstBuf[i]); 51 | } 52 | 53 | leftcrc = uint32_t(0); 54 | rightcrc = uint32_t(0); 55 | 56 | Utilities::ComputeCRC(tv, leftcrc, rightcrc); 57 | Audit::Assert(leftcrc == l); 58 | Audit::Assert(rightcrc == r); 59 | 60 | } 61 | 62 | }; 63 | } -------------------------------------------------------------------------------- /src/hermes/hermes.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/ndv2lib/ndsupport.h: -------------------------------------------------------------------------------- 1 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 2 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 3 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 4 | // PARTICULAR PURPOSE. 5 | // 6 | // Copyright (c) Microsoft Corporation. All rights reserved. 7 | // 8 | // Net Direct Helper Interface 9 | // 10 | 11 | #pragma once 12 | 13 | #ifndef _NETDIRECT_H_ 14 | #define _NETDIRECT_H_ 15 | 16 | #include "ndspi.h" 17 | #include "ndspi_ext_mlx.h" 18 | 19 | #ifdef __cplusplus 20 | extern "C" 21 | { 22 | #endif // __cplusplus 23 | 24 | #define ND_HELPER_API __stdcall 25 | 26 | 27 | // 28 | // Initialization 29 | // 30 | HRESULT ND_HELPER_API 31 | NdStartup( 32 | VOID 33 | ); 34 | 35 | HRESULT ND_HELPER_API 36 | NdCleanup( 37 | VOID 38 | ); 39 | 40 | VOID ND_HELPER_API 41 | NdFlushProviders( 42 | VOID 43 | ); 44 | 45 | // 46 | // Network capabilities 47 | // 48 | #define ND_QUERY_EXCLUDE_EMULATOR_ADDRESSES 0x00000001 49 | #define ND_QUERY_EXCLUDE_NDv1_ADDRESSES 0x00000002 50 | #define ND_QUERY_EXCLUDE_NDv2_ADDRESSES 0x00000004 51 | 52 | HRESULT ND_HELPER_API 53 | NdQueryAddressList( 54 | _In_ DWORD flags, 55 | _Out_opt_bytecap_post_bytecount_(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList, 56 | _Inout_ SIZE_T* pcbAddressList 57 | ); 58 | 59 | 60 | HRESULT ND_HELPER_API 61 | NdResolveAddress( 62 | _In_bytecount_(cbRemoteAddress) const struct sockaddr* pRemoteAddress, 63 | _In_ SIZE_T cbRemoteAddress, 64 | _Out_bytecap_(*pcbLocalAddress) struct sockaddr* pLocalAddress, 65 | _Inout_ SIZE_T* pcbLocalAddress 66 | ); 67 | 68 | 69 | HRESULT ND_HELPER_API 70 | NdCheckAddress( 71 | _In_bytecount_(cbAddress) const struct sockaddr* pAddress, 72 | _In_ SIZE_T cbAddress 73 | ); 74 | 75 | 76 | HRESULT ND_HELPER_API 77 | NdOpenAdapter( 78 | _In_ REFIID iid, 79 | _In_bytecount_(cbAddress) const struct sockaddr* pAddress, 80 | _In_ SIZE_T cbAddress, 81 | _Deref_out_ VOID** ppIAdapter 82 | ); 83 | 84 | 85 | HRESULT ND_HELPER_API 86 | NdOpenV1Adapter( 87 | _In_bytecount_(cbAddress) const struct sockaddr* pAddress, 88 | _In_ SIZE_T cbAddress, 89 | _Deref_out_ INDAdapter** ppIAdapter 90 | ); 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif // __cplusplus 95 | 96 | 97 | #endif // _NETDIRECT_H_ 98 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/hermes.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hermes", "hermes\hermes.vcxproj", "{AC9002B8-8526-4A0F-A77B-4AAD80350396}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958} = {81D74EE0-3C7F-4731-8208-3CA6ADD44958} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndv2lib", "ndv2lib\ndv2lib.vcxproj", "{81D74EE0-3C7F-4731-8208-3CA6ADD44958}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pingpong", "Pingpong\Pingpong.vcxproj", "{0F57C289-EFCB-4237-B160-06D03E1E7D2D}" 14 | ProjectSection(ProjectDependencies) = postProject 15 | {AC9002B8-8526-4A0F-A77B-4AAD80350396} = {AC9002B8-8526-4A0F-A77B-4AAD80350396} 16 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958} = {81D74EE0-3C7F-4731-8208-3CA6ADD44958} 17 | EndProjectSection 18 | EndProject 19 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "UnitTest\UnitTest.vcxproj", "{3FB1188B-58A6-45A8-AE20-CCBDC0E4720B}" 20 | EndProject 21 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mala", "..\extern\mala\src\lib\mala.vcxproj", "{FA7D4A3C-99C5-48AF-8537-6D47DB56C615}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|x64 = Debug|x64 26 | Release|x64 = Release|x64 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {AC9002B8-8526-4A0F-A77B-4AAD80350396}.Debug|x64.ActiveCfg = Debug|x64 30 | {AC9002B8-8526-4A0F-A77B-4AAD80350396}.Debug|x64.Build.0 = Debug|x64 31 | {AC9002B8-8526-4A0F-A77B-4AAD80350396}.Release|x64.ActiveCfg = Release|x64 32 | {AC9002B8-8526-4A0F-A77B-4AAD80350396}.Release|x64.Build.0 = Release|x64 33 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958}.Debug|x64.ActiveCfg = Debug|x64 34 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958}.Debug|x64.Build.0 = Debug|x64 35 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958}.Release|x64.ActiveCfg = Release|x64 36 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958}.Release|x64.Build.0 = Release|x64 37 | {0F57C289-EFCB-4237-B160-06D03E1E7D2D}.Debug|x64.ActiveCfg = Debug|x64 38 | {0F57C289-EFCB-4237-B160-06D03E1E7D2D}.Debug|x64.Build.0 = Debug|x64 39 | {0F57C289-EFCB-4237-B160-06D03E1E7D2D}.Release|x64.ActiveCfg = Release|x64 40 | {0F57C289-EFCB-4237-B160-06D03E1E7D2D}.Release|x64.Build.0 = Release|x64 41 | {3FB1188B-58A6-45A8-AE20-CCBDC0E4720B}.Debug|x64.ActiveCfg = Debug|x64 42 | {3FB1188B-58A6-45A8-AE20-CCBDC0E4720B}.Debug|x64.Build.0 = Debug|x64 43 | {3FB1188B-58A6-45A8-AE20-CCBDC0E4720B}.Release|x64.ActiveCfg = Release|x64 44 | {3FB1188B-58A6-45A8-AE20-CCBDC0E4720B}.Release|x64.Build.0 = Release|x64 45 | {FA7D4A3C-99C5-48AF-8537-6D47DB56C615}.Debug|x64.ActiveCfg = Debug|x64 46 | {FA7D4A3C-99C5-48AF-8537-6D47DB56C615}.Debug|x64.Build.0 = Debug|x64 47 | {FA7D4A3C-99C5-48AF-8537-6D47DB56C615}.Release|x64.ActiveCfg = Release|x64 48 | {FA7D4A3C-99C5-48AF-8537-6D47DB56C615}.Release|x64.Build.0 = Release|x64 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /src/ndv2lib/ndspi_ext_mlx.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | // Copyright (C) Mellanox Technologies, Ltd. 2001-2015. ALL RIGHTS RESERVED. 3 | 4 | Module Name: 5 | 6 | ndspi_ext_mlx.h 7 | 8 | Abstract: 9 | 10 | NetworkDirect Service Provider Interfaces 11 | Mellanox specific extensions 12 | 13 | Environment: 14 | 15 | User mode 16 | 17 | --*/ 18 | 19 | #pragma once 20 | 21 | #include "ndspi.h" 22 | 23 | // 24 | // IND2QueuePairsPool object 25 | // 26 | #undef INTERFACE 27 | #define INTERFACE IND2QueuePairsPool 28 | 29 | // {5FF5992A-B671-4976-A04D-FBE07776D1BE} 30 | DEFINE_GUID(IID_IND2QueuePairsPool, 31 | 0x5ff5992a, 0xb671, 0x4976, 0xa0, 0x4d, 0xfb, 0xe0, 0x77, 0x76, 0xd1, 0xbe); 32 | 33 | typedef struct _ND2_QUEUE_PAIRS_POOL_STATS { 34 | // Input - capacity of struct 35 | // Output - sizeof struct for which members got filled (rest will be zeroed) 36 | ULONG cbSizeOfStruct; 37 | 38 | // number of times that the pool was empty when CreateObjects was called 39 | ULONG64 cEmptyPool; 40 | 41 | // number of times that the pool was filled using background thread 42 | ULONG64 cImplicitFill; 43 | 44 | // number of times that CreateObjects was called 45 | ULONG64 cCreateCalls; 46 | 47 | } ND2_QUEUE_PAIRS_POOL_STATS; 48 | 49 | // 50 | // IND2QueuePairsPool - Mellanox specific extension 51 | // acquire using IND2Adapter::QueryInterface w/ IID_IND2QueuePairsPool 52 | // 53 | DECLARE_INTERFACE_(IND2QueuePairsPool, IUnknown) 54 | { 55 | // *** IUnknown methods *** 56 | IFACEMETHOD(QueryInterface)( 57 | THIS_ 58 | REFIID riid, 59 | __deref_out LPVOID* ppvObj 60 | ) PURE; 61 | 62 | IFACEMETHOD_(ULONG,AddRef)( 63 | THIS 64 | ) PURE; 65 | 66 | IFACEMETHOD_(ULONG,Release)( 67 | THIS 68 | ) PURE; 69 | 70 | // 71 | // GetSize 72 | // returns the current number of items in the pool 73 | // each item is an QueuePair with attached send/recv completion-queue 74 | // 75 | STDMETHOD(GetSize)( 76 | THIS_ 77 | __out ULONG* pPoolSize 78 | ) PURE; 79 | 80 | // 81 | // QueryStats 82 | // 83 | STDMETHOD(QueryStats)( 84 | THIS_ 85 | __inout ND2_QUEUE_PAIRS_POOL_STATS* pStats 86 | ) PURE; 87 | 88 | // 89 | // Must be called once before CreateObjects 90 | // note: call Fill() to force immediate pre allocation 91 | // 92 | STDMETHOD(SetLimits)( 93 | THIS_ 94 | ULONG nMinPoolSize, 95 | ULONG nMaxPoolSize 96 | ) PURE; 97 | 98 | // 99 | // Must be called once before CreateObjects 100 | // see MSDN IND2Adapter::CreateQueuePair for parameters info 101 | // 102 | STDMETHOD(SetQueuePairParams)( 103 | THIS_ 104 | VOID* context, 105 | ULONG receiveQueueDepth, 106 | ULONG initiatorQueueDepth, 107 | ULONG maxReceiveRequestSge, 108 | ULONG maxInitiatorRequestSge, 109 | ULONG inlineDataSize 110 | ) PURE; 111 | 112 | // 113 | // Must be called once before CreateObjects 114 | // see MSDN IND2Adapter::CreateCompletionQueue for parameters info 115 | // 116 | STDMETHOD(SetCompletionQueueParams)( 117 | THIS_ 118 | HANDLE hOverlappedFile, 119 | ULONG queueDepth, 120 | USHORT group, 121 | KAFFINITY affinity 122 | ) PURE; 123 | 124 | // 125 | // Call to assure that pool has at least nPoolSize items 126 | // after this call returns if bAsync == FALSE 127 | // 128 | STDMETHOD(Fill)( 129 | THIS_ 130 | ULONG nPoolSize, 131 | bool bAsync 132 | ) PURE; 133 | 134 | // 135 | // CreateObjects 136 | // 137 | STDMETHOD(CreateObjects)( 138 | THIS_ 139 | __deref_out IND2QueuePair** ppQp, 140 | __deref_out IND2CompletionQueue** ppCq 141 | ) PURE; 142 | 143 | }; 144 | 145 | #undef INTERFACE 146 | 147 | -------------------------------------------------------------------------------- /src/ndv2lib/ndv2lib.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {81D74EE0-3C7F-4731-8208-3CA6ADD44958} 15 | Win32Proj 16 | ndv2lib 17 | 8.1 18 | 19 | 20 | 21 | StaticLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | StaticLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Level4 49 | Disabled 50 | _DEBUG;_LIB;%(PreprocessorDefinitions) 51 | true 52 | 53 | 54 | Windows 55 | 56 | 57 | 58 | 59 | Level3 60 | MaxSpeed 61 | true 62 | true 63 | NDEBUG;_LIB;%(PreprocessorDefinitions) 64 | true 65 | 66 | 67 | Windows 68 | true 69 | true 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/ndv2lib/nddef.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Module Name: 6 | 7 | nddef.h 8 | 9 | Abstract: 10 | 11 | NetworkDirect Service Provider structure definitions 12 | 13 | Environment: 14 | 15 | User mode and kernel mode 16 | 17 | --*/ 18 | 19 | #ifndef _NDDEF_H_ 20 | #define _NDDEF_H_ 21 | 22 | #pragma once 23 | 24 | #define ND_VERSION_1 0x1 25 | #define ND_VERSION_2 0x20000 26 | 27 | #ifndef NDVER 28 | #define NDVER ND_VERSION_2 29 | #endif 30 | 31 | #define ND_ADAPTER_FLAG_IN_ORDER_DMA_SUPPORTED 0x00000001 32 | #define ND_ADAPTER_FLAG_CQ_INTERRUPT_MODERATION_SUPPORTED 0x00000004 33 | #define ND_ADAPTER_FLAG_MULTI_ENGINE_SUPPORTED 0x00000008 34 | #define ND_ADAPTER_FLAG_CQ_RESIZE_SUPPORTED 0x00000100 35 | #define ND_ADAPTER_FLAG_LOOPBACK_CONNECTIONS_SUPPORTED 0x00010000 36 | 37 | #define ND_CQ_NOTIFY_ERRORS 0 38 | #define ND_CQ_NOTIFY_ANY 1 39 | #define ND_CQ_NOTIFY_SOLICITED 2 40 | 41 | #define ND_MR_FLAG_ALLOW_LOCAL_WRITE 0x00000001 42 | #define ND_MR_FLAG_ALLOW_REMOTE_READ 0x00000002 43 | #define ND_MR_FLAG_ALLOW_REMOTE_WRITE 0x00000005 44 | #define ND_MR_FLAG_RDMA_READ_SINK 0x00000008 45 | #define ND_MR_FLAG_DO_NOT_SECURE_VM 0x80000000 46 | 47 | #define ND_OP_FLAG_SILENT_SUCCESS 0x00000001 48 | #define ND_OP_FLAG_READ_FENCE 0x00000002 49 | #define ND_OP_FLAG_SEND_AND_SOLICIT_EVENT 0x00000004 50 | #define ND_OP_FLAG_ALLOW_READ 0x00000008 51 | #define ND_OP_FLAG_ALLOW_WRITE 0x00000010 52 | #if NDVER >= ND_VERSION_2 53 | #define ND_OP_FLAG_INLINE 0x00000020 54 | #endif 55 | 56 | typedef struct _ND2_ADAPTER_INFO { 57 | ULONG InfoVersion; 58 | UINT16 VendorId; 59 | UINT16 DeviceId; 60 | UINT64 AdapterId; 61 | SIZE_T MaxRegistrationSize; 62 | SIZE_T MaxWindowSize; 63 | ULONG MaxInitiatorSge; 64 | ULONG MaxReceiveSge; 65 | ULONG MaxReadSge; 66 | ULONG MaxTransferLength; 67 | ULONG MaxInlineDataSize; 68 | ULONG MaxInboundReadLimit; 69 | ULONG MaxOutboundReadLimit; 70 | ULONG MaxReceiveQueueDepth; 71 | ULONG MaxInitiatorQueueDepth; 72 | ULONG MaxSharedReceiveQueueDepth; 73 | ULONG MaxCompletionQueueDepth; 74 | ULONG InlineRequestThreshold; 75 | ULONG LargeRequestThreshold; 76 | ULONG MaxCallerData; 77 | ULONG MaxCalleeData; 78 | ULONG AdapterFlags; 79 | } ND2_ADAPTER_INFO; 80 | 81 | typedef struct _ND2_ADAPTER_INFO32 { 82 | ULONG InfoVersion; 83 | UINT16 VendorId; 84 | UINT16 DeviceId; 85 | UINT64 AdapterId; 86 | ULONG MaxRegistrationSize; 87 | ULONG MaxWindowSize; 88 | ULONG MaxInitiatorSge; 89 | ULONG MaxReceiveSge; 90 | ULONG MaxReadSge; 91 | ULONG MaxTransferLength; 92 | ULONG MaxInlineDataSize; 93 | ULONG MaxInboundReadLimit; 94 | ULONG MaxOutboundReadLimit; 95 | ULONG MaxReceiveQueueDepth; 96 | ULONG MaxInitiatorQueueDepth; 97 | ULONG MaxSharedReceiveQueueDepth; 98 | ULONG MaxCompletionQueueDepth; 99 | ULONG InlineRequestThreshold; 100 | ULONG LargeRequestThreshold; 101 | ULONG MaxCallerData; 102 | ULONG MaxCalleeData; 103 | ULONG AdapterFlags; 104 | } ND2_ADAPTER_INFO32; 105 | 106 | typedef enum _ND2_REQUEST_TYPE { 107 | Nd2RequestTypeReceive, 108 | Nd2RequestTypeSend, 109 | Nd2RequestTypeBind, 110 | Nd2RequestTypeInvalidate, 111 | Nd2RequestTypeRead, 112 | Nd2RequestTypeWrite 113 | } ND2_REQUEST_TYPE; 114 | 115 | typedef struct _ND2_RESULT { 116 | HRESULT Status; 117 | ULONG BytesTransferred; 118 | VOID* QueuePairContext; 119 | VOID* RequestContext; 120 | ND2_REQUEST_TYPE RequestType; 121 | } ND2_RESULT; 122 | 123 | typedef struct _ND2_SGE { 124 | VOID* Buffer; 125 | ULONG BufferLength; 126 | UINT32 MemoryRegionToken; 127 | } ND2_SGE; 128 | 129 | #endif // _NDDEF_H_ 130 | -------------------------------------------------------------------------------- /src/hermes/Utilities.hpp: -------------------------------------------------------------------------------- 1 | // Utilities 2 | // 3 | 4 | #pragma once 5 | 6 | #include "stdafx.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "hermes.hpp" 17 | #include "Mem.hpp" 18 | #include "MiscWin.hpp" 19 | 20 | 21 | namespace Utilities 22 | { 23 | 24 | template 25 | struct ObjectPool 26 | { 27 | std::unique_ptr m_body; 28 | mbuf::CircularQue m_pool; 29 | 30 | ObjectPool(uint32_t size) 31 | : m_pool(size) 32 | , m_body(new T[size]) 33 | { 34 | for (auto i = 0ul; i < m_pool.GetCapacity(); i++) 35 | { 36 | Audit::Assert(m_pool.Add(&m_body[i]), 37 | L"Internal error, pool size mismatch."); 38 | } 39 | } 40 | 41 | T* Alloc() 42 | { 43 | T* ret; 44 | Audit::Assert(m_pool.Get(ret), 45 | L"Resource pool empty!"); 46 | return ret; 47 | } 48 | 49 | void Free(T* v) 50 | { 51 | Audit::Assert(m_pool.Add(v), L"Double free overflow!"); 52 | } 53 | }; 54 | 55 | 56 | const bool SKIP_CRC = false; 57 | 58 | inline void ComputeCRC(_In_ const gsl::span buf, _Inout_ uint32_t& leftcrc, _Inout_ uint32_t& rightcrc) 59 | { 60 | if (SKIP_CRC) return; 61 | 62 | auto size = size_t(buf.size_bytes()); 63 | Audit::Assert((size & 15) == 0, 64 | L"Need size alignment to 128b boundary for crc computation"); 65 | 66 | auto dSrc = buf.data(); 67 | Audit::Assert((uint64_t(dSrc) & 15) == 0, 68 | L"Need address alignment to 128b boundary for crc computation"); 69 | 70 | auto l = uint64_t(leftcrc); 71 | auto r = uint64_t(rightcrc); 72 | 73 | // sample one every cache line (64 bytes) 74 | for (size_t line = 0; line < size / 64; line ++) 75 | { 76 | auto first = reinterpret_cast(dSrc)[0]; 77 | auto second = reinterpret_cast(dSrc)[1]; 78 | 79 | l = _mm_crc32_u64(l, first); 80 | r = _mm_crc32_u64(r, second); 81 | 82 | dSrc += 64; 83 | } 84 | leftcrc = uint32_t(l); 85 | rightcrc = uint32_t(r); 86 | } 87 | 88 | // Compute CRC while copy memory 89 | inline void ComputeCRC( 90 | _Out_ gsl::spandst, 91 | _In_ const gsl::span src, 92 | _Inout_ uint32_t& leftcrc, _Inout_ uint32_t& rightcrc) 93 | { 94 | if (SKIP_CRC) 95 | { 96 | memcpy_s(dst.data(), dst.size_bytes(), src.data(), src.size_bytes()); 97 | return; 98 | } 99 | 100 | auto bound = size_t(dst.size_bytes()); 101 | auto size = size_t(src.size_bytes()); 102 | Audit::Assert((size & 15) == 0, 103 | L"Need alignment to 128b boundary for crc computation"); 104 | 105 | Audit::Assert(bound >= size, L"Write memory over bound"); 106 | 107 | auto dSrc = src.data(); 108 | Audit::Assert((uint64_t(dSrc) & 15) == 0, 109 | L"Need address alignment to 128b boundary for crc computation"); 110 | 111 | auto dDst = dst.data(); 112 | Audit::Assert((uint64_t(dDst) & 15) == 0, 113 | L"Need address alignment to 128b boundary for crc computation"); 114 | 115 | auto l = uint64_t(leftcrc); 116 | auto r = uint64_t(rightcrc); 117 | 118 | // sample one crc every cache line (64 bytes) 119 | for (size_t line = 0; line < size / 64; line++) 120 | { 121 | auto pSrc = reinterpret_cast(dSrc); 122 | auto pDst = reinterpret_cast<__m128i*>(dDst); 123 | 124 | auto a = _mm_load_si128(pSrc); 125 | auto b = _mm_load_si128(pSrc+1); 126 | auto c = _mm_load_si128(pSrc+2); 127 | auto d = _mm_load_si128(pSrc+3); 128 | 129 | auto first = reinterpret_cast(dSrc)[0]; 130 | auto second = reinterpret_cast(dSrc)[1]; 131 | 132 | _mm_store_si128(pDst, a); 133 | l = _mm_crc32_u64(l, first); 134 | 135 | _mm_store_si128(pDst+1, b); 136 | r = _mm_crc32_u64(r, second); 137 | 138 | _mm_store_si128(pDst+2, c); 139 | _mm_store_si128(pDst+3, d); 140 | 141 | dSrc += 64; 142 | dDst += 64; 143 | } 144 | 145 | auto remain = size & 63; 146 | if (remain > 0) 147 | { 148 | memcpy_s(dDst, remain, dSrc, remain); 149 | } 150 | 151 | leftcrc = uint32_t(l); 152 | rightcrc = uint32_t(r); 153 | } 154 | 155 | extern size_t ListIpAddresses(std::vector& ipAddrs); 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/hermes/NDUtils.cpp: -------------------------------------------------------------------------------- 1 | // NDUtiles.cpp : misc functions that interact directly with NDv2 2 | // 3 | // 4 | 5 | #pragma once 6 | #include "stdafx.h" 7 | 8 | #include "Utilities.hpp" 9 | #include "Tracer.hpp" 10 | #include "internal.hpp" 11 | 12 | using namespace Utilities; 13 | using namespace hermes; 14 | 15 | namespace hinternal 16 | { 17 | // Some adaptors support queue pairs pool, try get that interface, optional 18 | // Return null if we can not find that interface 19 | // 20 | IND2QueuePairsPool* GetQuePairPoolInterface(IND2Adapter* pAdapter, HANDLE adapterFile) 21 | { 22 | IND2QueuePairsPool* pQuePairPool = nullptr; 23 | 24 | auto hr = pAdapter->QueryInterface(IID_IND2QueuePairsPool, 25 | (LPVOID *)&pQuePairPool); 26 | if (FAILED(hr)) 27 | { 28 | Tracer::LogWarning(StatusCode(::GetLastError()), 29 | L"INDAdapter::QueryInterface for IID_IND2QueuePairsPool failed"); 30 | return nullptr; 31 | } 32 | // Init pool 33 | hr = pQuePairPool->SetLimits((QP_POOL_SIZE >> 2) * 3, 34 | (QP_POOL_SIZE >> 2) * 5); 35 | if (FAILED(hr)) { 36 | pQuePairPool->Release(); 37 | pQuePairPool = nullptr; 38 | NdCleanup(); 39 | Audit::OutOfLine::Fail(StatusCode(hr), 40 | L"Queue pairs pool set limit failed."); 41 | } 42 | 43 | hr = pQuePairPool->SetQueuePairParams(nullptr, 44 | MAX_OVERLAPPED_ENTRIES, 45 | MAX_OVERLAPPED_ENTRIES, 46 | MAX_SGE, 47 | MAX_SGE, 48 | 0); 49 | if (FAILED(hr)) 50 | { 51 | pQuePairPool->Release(); 52 | pQuePairPool = nullptr; 53 | NdCleanup(); 54 | Audit::OutOfLine::Fail(StatusCode(hr), 55 | L"Queue pairs pool set parameter failed."); 56 | } 57 | 58 | hr = pQuePairPool->SetCompletionQueueParams(adapterFile, 59 | MAX_OVERLAPPED_ENTRIES << 1, 60 | 0, 61 | 0); 62 | if (FAILED(hr)) 63 | { 64 | pQuePairPool->Release(); 65 | pQuePairPool = nullptr; 66 | NdCleanup(); 67 | Audit::OutOfLine::Fail(StatusCode(hr), 68 | L"Queue pairs pool set completion queue parameter failed."); 69 | } 70 | 71 | hr = pQuePairPool->Fill(QP_POOL_SIZE, true); 72 | if (FAILED(hr)) 73 | { 74 | pQuePairPool->Release(); 75 | pQuePairPool = nullptr; 76 | NdCleanup(); 77 | Audit::OutOfLine::Fail(StatusCode(hr), 78 | L"Queue pairs pool Fill failed."); 79 | } 80 | 81 | return pQuePairPool; 82 | } 83 | 84 | // Initialize completion que, que pair, and connector for an connection 85 | // 86 | StatusCode InitQues( 87 | // Optional que pair pool 88 | _In_ IND2QueuePairsPool* qpPool, 89 | 90 | // NDv2 Adpter 91 | _In_ IND2Adapter* pAdapter, 92 | 93 | // NDv2 adptor file handle 94 | _In_ HANDLE adapterFile, 95 | 96 | _Out_ IND2QueuePair*& pQuePair, 97 | _Out_ IND2CompletionQueue*& pCQ, 98 | _Out_ IND2Connector*& pConnector 99 | ) 100 | { 101 | HRESULT hr = E_UNEXPECTED; 102 | auto catchAll = Ctrl::scopeGuard([&] { 103 | Tracer::LogError(StatusCode(hr), 104 | L"Failed to prepare queues for connection."); 105 | }); 106 | 107 | if (nullptr != qpPool) 108 | { 109 | hr = qpPool->CreateObjects(&pQuePair, &pCQ); 110 | if (FAILED(hr)) 111 | { 112 | return StatusCode(hr); 113 | } 114 | } 115 | else 116 | { 117 | hr = pAdapter->CreateCompletionQueue(IID_IND2CompletionQueue, 118 | adapterFile, 119 | MAX_OVERLAPPED_ENTRIES << 1, 120 | 0, 121 | 0, 122 | reinterpret_cast(&pCQ)); 123 | 124 | if (FAILED(hr)) 125 | { 126 | return StatusCode(hr); 127 | } 128 | 129 | hr = pAdapter->CreateQueuePair(IID_IND2QueuePair, 130 | pCQ, 131 | pCQ, 132 | nullptr, 133 | MAX_OVERLAPPED_ENTRIES, 134 | MAX_OVERLAPPED_ENTRIES, 135 | MAX_SGE, 136 | MAX_SGE, 137 | 0, 138 | reinterpret_cast(&pQuePair)); 139 | if (FAILED(hr)) 140 | { 141 | return StatusCode(hr); 142 | } 143 | } 144 | 145 | hr = pAdapter->CreateConnector(IID_IND2Connector, 146 | adapterFile, 147 | reinterpret_cast(&pConnector)); 148 | if (!FAILED(hr)) 149 | { 150 | catchAll.dismiss(); 151 | } 152 | return StatusCode(hr); 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /src/hermes/internal.hpp: -------------------------------------------------------------------------------- 1 | // internal.hpp 2 | // Define internal data structure of hermes library 3 | 4 | #pragma once 5 | #include "stdafx.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "hermes.hpp" 11 | #include "Utilities.hpp" 12 | #include "Scheduler.hpp" 13 | 14 | #include "ndsupport.h" 15 | 16 | namespace hinternal 17 | { 18 | // Note: I am not complete sure about these const values due to limited 19 | // knowledge. Need to adjust later 20 | 21 | // Max completion queue depth 22 | const uint32_t MAX_OVERLAPPED_ENTRIES = 256; 23 | 24 | const uint32_t MAX_SGE = 32; 25 | 26 | const uint32_t QP_POOL_SIZE = 128; 27 | 28 | // A Terminal is the data structure for a connection. 29 | // We keep an terminal table and a socket table. as not all socket are 30 | // connected and need a terminal. Both indexes start from 1 31 | // 32 | const uint32_t INVALID_TERM_ID = 0; 33 | const uint32_t INVALID_SOCK_ID = 0; 34 | 35 | // Functor to process async notifications. 36 | // Since NDv2 providers would skip IOCP on success, we need to process 37 | // the completion both on sync return and async completion. 38 | // 39 | // !!! Must be allocated on an Arena!!! 40 | // Async -> always triggered by HermesFixedRIO::Run 41 | // Sync -> must be called by pass async opertion result code, and 42 | // the arena it is allocated on. 43 | // 44 | struct AsyncJob 45 | { 46 | // Actual logic for processing the async result. Sub class defining 47 | // this method must either reclaim pArena, or pass it to other 48 | // AsyncJob. 49 | // 50 | virtual void operator()( 51 | // Result code from GetOverlappedResult(); 52 | HRESULT hr, 53 | 54 | // Caller must provide the Arena on which this 55 | // object is allocated. 56 | _In_ Schedulers::ActionArena* pArena) = 0; 57 | }; 58 | 59 | template 60 | class AsyncLambda : public AsyncJob 61 | { 62 | Func f_; 63 | public: 64 | AsyncLambda(Func f) 65 | : f_(std::move(f)) 66 | {} 67 | 68 | ~AsyncLambda() {} 69 | 70 | void operator()( 71 | // Result code from GetOverlappedResult(); 72 | HRESULT hr, 73 | 74 | // Arena on which this object is allocated. 75 | _In_ Schedulers::ActionArena* pArena) override 76 | { 77 | f_(hr, pArena); 78 | } 79 | }; 80 | 81 | template 82 | AsyncJob* asyncLambda( 83 | // lambda function that define the async processing logic 84 | Func f, 85 | 86 | // memory arena on which this object is allocated 87 | Schedulers::ActionArena* pArena 88 | ) 89 | { 90 | return pArena->allocate>(std::move(f)); 91 | } 92 | 93 | 94 | // Attach pointers to async continuation at OVERLAPPED so that we 95 | // know where to go after an async notification. 96 | // 97 | struct HOverlap 98 | { 99 | OVERLAPPED OV; 100 | IND2Overlapped* PReceiver; 101 | AsyncJob *PNext; 102 | 103 | HOverlap() 104 | { 105 | std::memset(this, 0, sizeof(HOverlap)); 106 | } 107 | 108 | static HOverlap* GetContext(OVERLAPPED* pOv) 109 | { 110 | return reinterpret_cast 111 | (reinterpret_cast(pOv) - offsetof(HOverlap, OV)); 112 | } 113 | }; 114 | 115 | struct HOverlapPool 116 | { 117 | Utilities::ObjectPool m_pool; 118 | 119 | HOverlapPool(uint32_t size) 120 | : m_pool(size) 121 | {} 122 | 123 | HOverlap* GetObj(AsyncJob* pjob, IND2Overlapped* pReceiver) 124 | { 125 | auto ret = m_pool.Alloc(); 126 | Audit::Assert(ret->PNext == nullptr 127 | && ret->PReceiver == nullptr, 128 | L"Object stat changed while in pool!"); 129 | ret->PNext = pjob; 130 | ret->PReceiver = pReceiver; 131 | return ret; 132 | } 133 | 134 | void FreeObj(HOverlap* v) 135 | { 136 | Audit::Assert(v->PNext != nullptr 137 | || v->PReceiver != nullptr, 138 | L"Double free!"); 139 | new(v) HOverlap(); 140 | m_pool.Free(v); 141 | } 142 | }; 143 | 144 | 145 | // Send request 146 | struct SndReq { 147 | void* m_context; 148 | gsl::span m_buf; 149 | hermes::SendCompletionNotifier* m_pCallback; 150 | }; 151 | 152 | extern IND2QueuePairsPool* GetQuePairPoolInterface(IND2Adapter* pAdapter, HANDLE adapterFile); 153 | 154 | // Initialize completion que, que pair, and connector for an connection 155 | // 156 | extern StatusCode InitQues( 157 | // Optional que pair pool 158 | _In_ IND2QueuePairsPool* qpPool, 159 | 160 | // NDv2 Adpter 161 | _In_ IND2Adapter* pAdapter, 162 | 163 | // NDv2 adptor file handle 164 | _In_ HANDLE adapterFile, 165 | 166 | _Out_ IND2QueuePair*& pQuePair, 167 | _Out_ IND2CompletionQueue*& pCQ, 168 | _Out_ IND2Connector*& pConnector 169 | ); 170 | 171 | } -------------------------------------------------------------------------------- /src/hermes/UtilitiesWin.cpp: -------------------------------------------------------------------------------- 1 | // NetBursts.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #pragma once 5 | 6 | #include "stdafx.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Audit.hpp" 14 | #include "MiscWin.hpp" 15 | #include "Utilities.hpp" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | namespace Utilities 25 | { 26 | 27 | // Inspect the system and figure out all the IP Addresses we might be using. 28 | // 29 | size_t ListIpAddresses(vector& ipAddrs) 30 | { 31 | ipAddrs.clear(); 32 | 33 | IP_ADAPTER_ADDRESSES adapterAddresses[256]; 34 | ULONG adapterAddressesSize{ sizeof(adapterAddresses) }; 35 | 36 | DWORD error = ::GetAdaptersAddresses( 37 | AF_INET, 38 | GAA_FLAG_SKIP_ANYCAST | 39 | GAA_FLAG_SKIP_MULTICAST | 40 | GAA_FLAG_SKIP_DNS_SERVER | 41 | GAA_FLAG_SKIP_FRIENDLY_NAME, 42 | nullptr, 43 | adapterAddresses, 44 | &adapterAddressesSize); 45 | 46 | if (ERROR_SUCCESS != error) 47 | { 48 | return 0; 49 | } 50 | 51 | // Iterate through all of the adapters 52 | for (IP_ADAPTER_ADDRESSES* adapter = adapterAddresses; nullptr != adapter; adapter = adapter->Next) 53 | { 54 | // Skip loopback and none-working adaptors 55 | if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType || IfOperStatusUp != adapter->OperStatus) 56 | { 57 | continue; 58 | } 59 | 60 | // Parse all IPv4 and IPv6 addresses 61 | for (IP_ADAPTER_UNICAST_ADDRESS* unicaster = adapter->FirstUnicastAddress; nullptr != unicaster; unicaster = unicaster->Next) 62 | { 63 | auto family = unicaster->Address.lpSockaddr->sa_family; 64 | if (AF_INET == family) 65 | { 66 | // IPv4 67 | ipAddrs.push_back(reinterpret_cast(unicaster->Address.lpSockaddr)->sin_addr); 68 | } 69 | else if (AF_INET6 == family) 70 | { 71 | // Skip all other types of addresses 72 | continue; 73 | } 74 | } 75 | } 76 | return ipAddrs.size(); 77 | } 78 | 79 | } 80 | 81 | namespace mbuf 82 | { 83 | void EnableLargePages() 84 | { 85 | HANDLE hToken; 86 | TOKEN_PRIVILEGES tp; 87 | 88 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 89 | { 90 | Audit::OutOfLine::Fail((StatusCode)GetLastError()); 91 | } 92 | // the app needs to run at elevated privilege, with local security policy allowing memory locking. 93 | auto closer = Ctrl::AutoClose(hToken, 94 | [&] { 95 | if (!LookupPrivilegeValue(nullptr, TEXT("SeLockMemoryPrivilege"), &tp.Privileges[0].Luid)) 96 | { 97 | Audit::OutOfLine::Fail((StatusCode)::GetLastError()); 98 | } 99 | tp.PrivilegeCount = 1; 100 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 101 | AdjustTokenPrivileges(hToken, FALSE, &tp, 0, nullptr, 0); 102 | // AdjustToken silently fails, so we always need to check last status. 103 | auto status = (StatusCode)::GetLastError(); 104 | if (status != H_ok) 105 | { 106 | if (status == (StatusCode)ERROR_PRIVILEGE_NOT_HELD) 107 | Audit::OutOfLine::Fail(L"run at elevated privilege, with local security policy allowing memory locking"); 108 | else 109 | Audit::OutOfLine::Fail((StatusCode)status); 110 | } 111 | }); 112 | } 113 | 114 | /* Allocate multiple units of buffers contiguously in large pages which will stay resident 115 | */ 116 | LargePageBuffer::LargePageBuffer( 117 | const size_t oneBufferSize, 118 | const unsigned bufferCount, 119 | __out size_t& allocatedSize, 120 | __out unsigned& allocatedBufferCount 121 | ) 122 | { 123 | m_pBuffer = nullptr; 124 | m_allocatedSize = 0; 125 | const size_t granularity = ::GetLargePageMinimum(); 126 | const size_t minimumSize = oneBufferSize * bufferCount; 127 | allocatedSize = (minimumSize + granularity - 1) & (0 - granularity); 128 | allocatedBufferCount = 0; 129 | 130 | m_pBuffer = ::VirtualAlloc( 131 | nullptr, 132 | allocatedSize, 133 | MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, 134 | PAGE_READWRITE 135 | ); 136 | 137 | if (m_pBuffer != nullptr) 138 | { 139 | m_allocatedSize = allocatedSize; 140 | allocatedBufferCount = (int)(allocatedSize / oneBufferSize); 141 | } 142 | else 143 | { 144 | Audit::OutOfLine::Fail((StatusCode)::GetLastError(), L"Cannot allocate large page!"); 145 | } 146 | } 147 | 148 | LargePageBuffer::~LargePageBuffer() 149 | { 150 | if (m_pBuffer != nullptr) 151 | { 152 | ::VirtualFreeEx(GetCurrentProcess(), m_pBuffer, m_allocatedSize, 0); 153 | m_pBuffer = nullptr; 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/hermes/hermes.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {AC9002B8-8526-4A0F-A77B-4AAD80350396} 15 | Win32Proj 16 | hermes 17 | 8.1 18 | 19 | 20 | 21 | StaticLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | StaticLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | $(ProjectDir)..\ndv2lib;$(SolutionDir)..\extern\GSL\gsl;$(SolutionDir)..\extern\mala\src\inc;$(IncludePath) 47 | 48 | 49 | $(ProjectDir)..\ndv2lib;$(SolutionDir)..\extern\GSL\gsl;$(SolutionDir)..\extern\mala\src\inc;$(IncludePath) 50 | 51 | 52 | 53 | Use 54 | Level4 55 | Disabled 56 | _DEBUG;_LIB;%(PreprocessorDefinitions) 57 | true 58 | 59 | 60 | Windows 61 | 62 | 63 | $(SolutionDir)..\GetDependencies.bat 64 | 65 | 66 | 67 | 68 | Level3 69 | Use 70 | MaxSpeed 71 | true 72 | true 73 | NDEBUG;_LIB;%(PreprocessorDefinitions) 74 | true 75 | 76 | 77 | Windows 78 | true 79 | true 80 | 81 | 82 | $(SolutionDir)..\GetDependencies.bat 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | Create 100 | Create 101 | 102 | 103 | 104 | 105 | 106 | {fa7d4a3c-99c5-48af-8537-6d47db56c615} 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/Pingpong/Pingpong.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {0F57C289-EFCB-4237-B160-06D03E1E7D2D} 15 | Win32Proj 16 | Pingpong 17 | 8.1 18 | 19 | 20 | 21 | Application 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | $(ProjectDir)..\hermes;$(SolutionDir)..\extern\GSL\include;$(IncludePath) 48 | 49 | 50 | false 51 | $(ProjectDir)..\hermes;$(SolutionDir)..\extern\GSL\include;$(IncludePath) 52 | 53 | 54 | 55 | Use 56 | Level4 57 | Disabled 58 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 59 | true 60 | 61 | 62 | Console 63 | true 64 | Ws2_32.lib;Iphlpapi.lib;Pathcch.lib;%(AdditionalDependencies) 65 | RequireAdministrator 66 | 67 | 68 | 69 | 70 | Level3 71 | Use 72 | MaxSpeed 73 | true 74 | true 75 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 76 | true 77 | 78 | 79 | Console 80 | true 81 | true 82 | true 83 | Ws2_32.lib;Iphlpapi.lib;Pathcch.lib;%(AdditionalDependencies) 84 | RequireAdministrator 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Create 98 | Create 99 | 100 | 101 | 102 | 103 | {ac9002b8-8526-4a0f-a77b-4aad80350396} 104 | 105 | 106 | {81d74ee0-3c7f-4731-8208-3ca6add44958} 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/UnitTest/UnitTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {3FB1188B-58A6-45A8-AE20-CCBDC0E4720B} 15 | Win32Proj 16 | UnitTest 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | false 26 | 27 | 28 | DynamicLibrary 29 | false 30 | v140 31 | true 32 | Unicode 33 | false 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | true 55 | $(SolutionDir)..\extern\GSL\include;$(ProjectDir)..\hermes;$(IncludePath) 56 | 57 | 58 | true 59 | $(SolutionDir)..\extern\GSL\include;$(ProjectDir)..\hermes;$(IncludePath) 60 | 61 | 62 | 63 | Use 64 | Level3 65 | Disabled 66 | $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) 67 | _DEBUG;%(PreprocessorDefinitions) 68 | true 69 | 70 | 71 | Windows 72 | true 73 | $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) 74 | Ws2_32.lib;Iphlpapi.lib;Pathcch.lib;%(AdditionalDependencies) 75 | 76 | 77 | 78 | 79 | Level3 80 | Use 81 | MaxSpeed 82 | true 83 | true 84 | $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) 85 | NDEBUG;%(PreprocessorDefinitions) 86 | true 87 | 88 | 89 | Windows 90 | true 91 | true 92 | true 93 | $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) 94 | Ws2_32.lib;Iphlpapi.lib;Pathcch.lib;%(AdditionalDependencies) 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Create 104 | Create 105 | 106 | 107 | 108 | 109 | 110 | {ac9002b8-8526-4a0f-a77b-4aad80350396} 111 | 112 | 113 | {81d74ee0-3c7f-4731-8208-3ca6add44958} 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/hermes/hermes.hpp: -------------------------------------------------------------------------------- 1 | // hermes.hpp Defines API supported by hermes library 2 | // 3 | 4 | #pragma once 5 | 6 | #include "stdafx.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "Audit.hpp" 12 | #include "Mem.hpp" 13 | 14 | namespace hermes 15 | { 16 | // Socket Handle 17 | using HSocketHandle = intptr_t; 18 | 19 | // Message size must align to 16 byte boundary 20 | const size_t MSG_ALIGN = 16; 21 | 22 | // Max message size supported 1023M 23 | const size_t MAX_MSG_SIZE = 1023 * 1024 * 1024; 24 | 25 | ///////////////////////////////////////////////////////////////////// 26 | // Async call backs for network events 27 | // 28 | // One problem with this library is that we can not tolerate any 29 | // long running computation or blocking operations in these 30 | // callbacks. Doing so would cause severe perf degradation, 31 | // resources depletion or even application crash. 32 | // 33 | // We need to add enforcement in the future. 34 | // 35 | 36 | // Called when an new connection is established or an connected 37 | // socket is disconnected 38 | // 39 | class ConnectionNotifier 40 | { 41 | public: 42 | virtual void operator() ( 43 | // Socket that holds the new connection 44 | _In_ HSocketHandle pSocket, 45 | 46 | _In_ StatusCode status 47 | ) = 0; 48 | }; 49 | 50 | // Called when a message is received. Must return quickly. In this 51 | // version, any delay in this method would stall transportation 52 | // and hurt performance. 53 | // 54 | class RcvNotifier 55 | { 56 | public: 57 | virtual void operator() ( 58 | // Socket that holds the connection 59 | HSocketHandle pSocket, 60 | 61 | // An reclaimable buffer that contains the message 62 | // User must call pBuf->Dispose() to release it 63 | // after finished processing the message. 64 | // 65 | _In_ mbuf::DisposableBuffer* pBuf, 66 | 67 | StatusCode status 68 | ) = 0; 69 | }; 70 | 71 | // Notify sender an async send operation completed, buffer 72 | // can be released 73 | // 74 | class SendCompletionNotifier 75 | { 76 | public: 77 | virtual void operator() ( 78 | // Indicate result of the send operation 79 | StatusCode status, 80 | 81 | // parameters provided to the original send operation 82 | _In_ void* sndContext, 83 | _In_ const gsl::span buf 84 | ) = 0; 85 | }; 86 | 87 | // End callbacks 88 | ///////////////////////////////////////////////////////////////////// 89 | 90 | // Entry point of the hermes library. 91 | // In this version only one instance can be instantiated due to tight 92 | // binding with NDv2. 93 | // 94 | class Hermes 95 | { 96 | public: 97 | // Each Hermes instance is bind to one IP. Currently only IPv4 98 | // is supported. 99 | // 100 | virtual uint32_t GetHomeIp() = 0; 101 | 102 | // Create a new socket ==> WSA socket 103 | // Only IPv4 is supported in this version 104 | // Automatically binded, no "bind" function needed 105 | // 106 | virtual HSocketHandle CreateSocket( 107 | _Out_ StatusCode& error 108 | ) = 0; 109 | 110 | // Only valid for socket in connected or listening state 111 | // returns 0 when unknown. 112 | virtual uint16_t GetHomePort(HSocketHandle) = 0; 113 | 114 | // Only valid for connected sockets, return 0 when unknown. 115 | virtual uint32_t GetRemoteIp(HSocketHandle) = 0; 116 | virtual uint16_t GetRemotePort(HSocketHandle) = 0; 117 | 118 | // Begin Listen on a certain port. ==> WSA listen 119 | // automatically assigned if 0 120 | // 121 | virtual StatusCode Listen(HSocketHandle sock, uint16_t port) = 0; 122 | 123 | // Signal that one connection can be accepted. ==> WSA accept 124 | // new socket of the newly established connection is provided async 125 | // by connectionCallback 126 | // 127 | virtual StatusCode Accept( 128 | HSocketHandle sock, 129 | 130 | // hook for Async return of the connected socket 131 | _In_ ConnectionNotifier& connectCallback, 132 | 133 | // A receive call back, will be assigned to the connected 134 | // socket, and triggered whenever a new message received 135 | // on that connected socket. 136 | // 137 | _In_ RcvNotifier& rcvCallback 138 | ) = 0; 139 | 140 | // Async call to connecting to a remote end point ==> WSA connect 141 | // new socket of the newly established connection is provided async 142 | // by connectionCallback 143 | virtual StatusCode Connect( 144 | HSocketHandle sock, 145 | 146 | uint32_t remoteIp, 147 | uint16_t remotePort, 148 | 149 | // hook for async notification of connection success or failure 150 | // socket parameter should be this socket. 151 | _In_ ConnectionNotifier& connectCallback, 152 | 153 | // A receive call back, once connected, new messages received 154 | // will trigger this 155 | // 156 | _In_ RcvNotifier& rcvCallback 157 | ) = 0; 158 | 159 | // Async send, notification of completion will be carried by 160 | // sendCallback provided to Connect or Accept method 161 | // 162 | virtual StatusCode Send( 163 | HSocketHandle sock, 164 | 165 | // place holder for the client to identify this operation 166 | // will be pass back to client in sendCallback 167 | _In_ void* sndContext, 168 | 169 | // Buffer must be available for the duration of the async 170 | // operation, until notified by sendCallback 171 | _In_ const gsl::span buf, 172 | 173 | // A send status call back, async notification of send completion 174 | _In_ SendCompletionNotifier& sendCallback 175 | ) = 0; 176 | 177 | // Close the socket. handle becomes invalid 178 | virtual void CloseSocket(HSocketHandle sock, 179 | StatusCode reason = H_ok) = 0; 180 | }; 181 | 182 | // Construct the root of this library, ==> WSAStartup() 183 | // 184 | extern std::unique_ptr HermesFixedRIOFactory( 185 | // Size of buffer allocated per connection. 186 | // will be split equally for sending and receiving 187 | // 188 | size_t conBufSize, 189 | 190 | // Number of concurrent connections. Need this now 191 | // since we don't have dynamic management yet. 192 | // 193 | uint32_t maxConnections 194 | ); 195 | 196 | } -------------------------------------------------------------------------------- /src/hermes/FixMem.cpp: -------------------------------------------------------------------------------- 1 | // FixMem.cpp a simple implemenation of a memory buffer allocator 2 | // using a fixed number of fixed size bufferes. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "stdafx.h" 8 | 9 | #include "FMem.hpp" 10 | #include "Utilities.hpp" 11 | 12 | namespace mbuf 13 | { 14 | // An aligned buffer allocated from heap. Not copiable 15 | // 16 | class HeapBuffer : public DisposableBuffer 17 | { 18 | private: 19 | uint32_t const m_blobSize; 20 | uint32_t m_offset; 21 | 22 | HeapBuffer(uint32_t size, uint32_t offset) 23 | : m_blobSize(size) 24 | , m_offset(offset) 25 | {} 26 | 27 | HeapBuffer& operator=(const HeapBuffer&) = delete; 28 | HeapBuffer(const HeapBuffer&) = delete; 29 | public: 30 | void Dispose() override 31 | { 32 | ::_aligned_free(PStart()); 33 | } 34 | 35 | void* PStart() const override 36 | { 37 | return (char*)this - m_blobSize; 38 | } 39 | 40 | uint32_t Offset() const override { return m_offset; } 41 | void SetOffset(size_t v) override 42 | { 43 | Audit::Assert(v < (1ull << 32)); 44 | m_offset = (uint32_t)v; 45 | } 46 | 47 | uint32_t Size() const override { return m_blobSize; } 48 | 49 | static DisposableBuffer* Allocate(uint32_t dataBlobSize, uint32_t alignment = 8, uint32_t offset = 0) 50 | { 51 | Audit::Assert(mbuf::IsPower2(alignment), 52 | L"Alignment must be a power of 2"); 53 | 54 | void* buf = ::_aligned_malloc(dataBlobSize + sizeof(HeapBuffer), alignment); 55 | Audit::Assert(buf != nullptr, 56 | L"can not allocate memory from heap!"); 57 | 58 | // stick the recycler at the end of the buffer to keep data buffer aligned 59 | HeapBuffer* ret = new ((char*)buf + dataBlobSize)HeapBuffer(dataBlobSize, offset); 60 | return ret; 61 | } 62 | }; 63 | 64 | 65 | // Disposabuffers are allocated to carry network messages, 66 | // and read data from SSD. Most of the time these data are 67 | // small and transient. We use these buffer pools to reduce 68 | // memory churn, only go to heap for big ones. 69 | // 70 | // Worth it to implement a buddy system? Either allocation 71 | // or free would be slow. 72 | // 73 | template 74 | class SmallBufferPool 75 | { 76 | private: 77 | static_assert((BUF_SIZE & (BUF_SIZE - 1)) == 0, 78 | "Buffer size must be power of 2."); 79 | 80 | struct SmallBuffer : public DisposableBuffer 81 | { 82 | SmallBufferPool* m_pPool = nullptr; 83 | uint32_t m_size = 0; 84 | uint32_t m_offset = 0; 85 | 86 | SmallBuffer& operator=(const SmallBuffer&) = delete; 87 | SmallBuffer(const SmallBuffer&) = delete; 88 | 89 | SmallBuffer() {} 90 | 91 | void Dispose() override 92 | { 93 | m_pPool->Release(this); 94 | } 95 | 96 | void* PStart() const override 97 | { 98 | return m_pPool->GetData(this); 99 | } 100 | 101 | uint32_t Offset() const override { return m_offset; } 102 | void SetOffset(size_t v) override 103 | { 104 | Audit::Assert(v < m_size); 105 | m_offset = (uint32_t)v; 106 | } 107 | 108 | uint32_t Size() const override { return m_size; } 109 | }; 110 | 111 | SmallBuffer m_body[NUM_BUFS]; 112 | mbuf::CircularQue m_free; 113 | std::unique_ptr m_pMemory; 114 | 115 | void* GetData(const SmallBuffer* pBuf) 116 | { 117 | Audit::Assert(pBuf->m_size != 0, 118 | L"Access Released Buffer!"); 119 | auto index = pBuf - m_body; 120 | Audit::Assert(index < m_free.GetCapacity(), 121 | L"Buffer released to wrong pool!"); 122 | 123 | return &(m_pMemory->GetData()[index * BUF_SIZE]); 124 | } 125 | 126 | void Release(SmallBuffer* pBuf) 127 | { 128 | Audit::Assert(pBuf->m_size != 0, 129 | L"Double buffer release detected!"); 130 | pBuf->m_size = 0; 131 | pBuf->m_offset = 0; 132 | 133 | auto index = pBuf - m_body; 134 | Audit::Assert(&m_body[index] == pBuf, 135 | L"Internal error in pointer arithmetic."); 136 | Audit::Assert(index < m_free.GetCapacity(), 137 | L"Buffer released to wrong pool!"); 138 | m_free.Add((uint32_t)index); 139 | } 140 | 141 | public: 142 | SmallBufferPool() 143 | : m_free(NUM_BUFS) 144 | { 145 | size_t allocatedSize; 146 | uint32_t actualCount; 147 | m_pMemory = std::make_unique 148 | (BUF_SIZE, NUM_BUFS, allocatedSize, actualCount); 149 | Audit::Assert(actualCount == NUM_BUFS, 150 | L"Ill formed large page size for buffer pool"); 151 | 152 | for (uint32_t i = 0; i < NUM_BUFS; i++) { 153 | m_body[i].m_pPool = this; 154 | m_free.Add(i); 155 | } 156 | } 157 | 158 | uint32_t BufSizeLimit() 159 | { 160 | return BUF_SIZE; 161 | } 162 | 163 | DisposableBuffer* Allocate(uint32_t dataBlobSize, uint32_t alignment = 8, uint32_t offset = 0) 164 | { 165 | Audit::Assert(dataBlobSize > 0, L"Can not allocate empty buffer."); 166 | Audit::Assert(dataBlobSize <= BUF_SIZE, 167 | L"Allocation buffer size too big."); 168 | Audit::Assert(alignment <= BUF_SIZE && ((alignment & (alignment - 1)) == 0), 169 | L"Buffer aligenment requirement can not be met!"); 170 | auto index = UINT32_MAX; 171 | Audit::Assert(m_free.Get(index), L"Small Buffer Pool empty."); 172 | m_body[index].m_offset = offset; 173 | m_body[index].m_size = dataBlobSize; 174 | return &m_body[index]; 175 | } 176 | }; 177 | 178 | 179 | class FixedBufManager : public BufManager 180 | { 181 | // Small buffer pools to reduce memory churn. 182 | SmallBufferPool<2 * SI::Ki, 1024> m_sPool; 183 | SmallBufferPool<8 * SI::Ki, 1024> m_mPool; 184 | SmallBufferPool<32 * SI::Ki, 1024> m_bPool; 185 | 186 | public: 187 | FixedBufManager() = default; 188 | 189 | DisposableBuffer* Allocate( 190 | uint32_t size, 191 | uint32_t alignment = 8, 192 | uint32_t offset = 0) override 193 | { 194 | if (size <= m_sPool.BufSizeLimit() && alignment <= m_sPool.BufSizeLimit()) { 195 | return m_sPool.Allocate(size, alignment, offset); 196 | } 197 | else if (size <= m_mPool.BufSizeLimit() && alignment <= m_mPool.BufSizeLimit()) { 198 | return m_mPool.Allocate(size, alignment, offset); 199 | } 200 | else if (size <= m_bPool.BufSizeLimit() && alignment <= m_bPool.BufSizeLimit()) { 201 | return m_bPool.Allocate(size, alignment, offset); 202 | } 203 | else { 204 | return HeapBuffer::Allocate(size, alignment, offset); 205 | } 206 | } 207 | 208 | }; 209 | 210 | std::unique_ptr FixedBufManagerFactory() 211 | { 212 | return std::make_unique(); 213 | } 214 | } -------------------------------------------------------------------------------- /src/ndv2lib/ndstatus.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | ndstatus.h - NetworkDirect Status Codes 6 | 7 | Status codes with a facility of System map to NTSTATUS codes 8 | of similar names. 9 | 10 | --*/ 11 | 12 | #ifndef _NDSTATUS_ 13 | #define _NDSTATUS_ 14 | 15 | #pragma once 16 | 17 | 18 | // 19 | // Values are 32 bit values laid out as follows: 20 | // 21 | // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 22 | // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 23 | // +---+-+-+-----------------------+-------------------------------+ 24 | // |Sev|C|R| Facility | Code | 25 | // +---+-+-+-----------------------+-------------------------------+ 26 | // 27 | // where 28 | // 29 | // Sev - is the severity code 30 | // 31 | // 00 - Success 32 | // 01 - Informational 33 | // 10 - Warning 34 | // 11 - Error 35 | // 36 | // C - is the Customer code flag 37 | // 38 | // R - is a reserved bit 39 | // 40 | // Facility - is the facility code 41 | // 42 | // Code - is the facility's status code 43 | // 44 | // 45 | // Define the facility codes 46 | // 47 | 48 | 49 | // 50 | // Define the severity codes 51 | // 52 | #define STATUS_SEVERITY_WARNING 0x2 53 | #define STATUS_SEVERITY_SUCCESS 0x0 54 | #define STATUS_SEVERITY_INFORMATIONAL 0x1 55 | #define STATUS_SEVERITY_ERROR 0x3 56 | 57 | 58 | // 59 | // MessageId: ND_SUCCESS 60 | // 61 | // MessageText: 62 | // 63 | // ND_SUCCESS 64 | // 65 | #define ND_SUCCESS ((HRESULT)0x00000000L) 66 | 67 | // 68 | // MessageId: ND_TIMEOUT 69 | // 70 | // MessageText: 71 | // 72 | // ND_TIMEOUT 73 | // 74 | #define ND_TIMEOUT ((HRESULT)0x00000102L) 75 | 76 | // 77 | // MessageId: ND_PENDING 78 | // 79 | // MessageText: 80 | // 81 | // ND_PENDING 82 | // 83 | #define ND_PENDING ((HRESULT)0x00000103L) 84 | 85 | // 86 | // MessageId: ND_BUFFER_OVERFLOW 87 | // 88 | // MessageText: 89 | // 90 | // ND_BUFFER_OVERFLOW 91 | // 92 | #define ND_BUFFER_OVERFLOW ((HRESULT)0x80000005L) 93 | 94 | // 95 | // MessageId: ND_DEVICE_BUSY 96 | // 97 | // MessageText: 98 | // 99 | // ND_DEVICE_BUSY 100 | // 101 | #define ND_DEVICE_BUSY ((HRESULT)0x80000011L) 102 | 103 | // 104 | // MessageId: ND_NO_MORE_ENTRIES 105 | // 106 | // MessageText: 107 | // 108 | // ND_NO_MORE_ENTRIES 109 | // 110 | #define ND_NO_MORE_ENTRIES ((HRESULT)0x8000001AL) 111 | 112 | // 113 | // MessageId: ND_UNSUCCESSFUL 114 | // 115 | // MessageText: 116 | // 117 | // ND_UNSUCCESSFUL 118 | // 119 | #define ND_UNSUCCESSFUL ((HRESULT)0xC0000001L) 120 | 121 | // 122 | // MessageId: ND_ACCESS_VIOLATION 123 | // 124 | // MessageText: 125 | // 126 | // ND_ACCESS_VIOLATION 127 | // 128 | #define ND_ACCESS_VIOLATION ((HRESULT)0xC0000005L) 129 | 130 | // 131 | // MessageId: ND_INVALID_HANDLE 132 | // 133 | // MessageText: 134 | // 135 | // ND_INVALID_HANDLE 136 | // 137 | #define ND_INVALID_HANDLE ((HRESULT)0xC0000008L) 138 | 139 | // 140 | // MessageId: ND_INVALID_DEVICE_REQUEST 141 | // 142 | // MessageText: 143 | // 144 | // ND_INVALID_DEVICE_REQUEST 145 | // 146 | #define ND_INVALID_DEVICE_REQUEST ((HRESULT)0xC0000010L) 147 | 148 | // 149 | // MessageId: ND_INVALID_PARAMETER 150 | // 151 | // MessageText: 152 | // 153 | // ND_INVALID_PARAMETER 154 | // 155 | #define ND_INVALID_PARAMETER ((HRESULT)0xC000000DL) 156 | 157 | // 158 | // MessageId: ND_NO_MEMORY 159 | // 160 | // MessageText: 161 | // 162 | // ND_NO_MEMORY 163 | // 164 | #define ND_NO_MEMORY ((HRESULT)0xC0000017L) 165 | 166 | // 167 | // MessageId: ND_INVALID_PARAMETER_MIX 168 | // 169 | // MessageText: 170 | // 171 | // ND_INVALID_PARAMETER_MIX 172 | // 173 | #define ND_INVALID_PARAMETER_MIX ((HRESULT)0xC0000030L) 174 | 175 | // 176 | // MessageId: ND_DATA_OVERRUN 177 | // 178 | // MessageText: 179 | // 180 | // ND_DATA_OVERRUN 181 | // 182 | #define ND_DATA_OVERRUN ((HRESULT)0xC000003CL) 183 | 184 | // 185 | // MessageId: ND_SHARING_VIOLATION 186 | // 187 | // MessageText: 188 | // 189 | // ND_SHARING_VIOLATION 190 | // 191 | #define ND_SHARING_VIOLATION ((HRESULT)0xC0000043L) 192 | 193 | // 194 | // MessageId: ND_INSUFFICIENT_RESOURCES 195 | // 196 | // MessageText: 197 | // 198 | // ND_INSUFFICIENT_RESOURCES 199 | // 200 | #define ND_INSUFFICIENT_RESOURCES ((HRESULT)0xC000009AL) 201 | 202 | // 203 | // MessageId: ND_DEVICE_NOT_READY 204 | // 205 | // MessageText: 206 | // 207 | // ND_DEVICE_NOT_READY 208 | // 209 | #define ND_DEVICE_NOT_READY ((HRESULT)0xC00000A3L) 210 | 211 | // 212 | // MessageId: ND_IO_TIMEOUT 213 | // 214 | // MessageText: 215 | // 216 | // ND_IO_TIMEOUT 217 | // 218 | #define ND_IO_TIMEOUT ((HRESULT)0xC00000B5L) 219 | 220 | // 221 | // MessageId: ND_NOT_SUPPORTED 222 | // 223 | // MessageText: 224 | // 225 | // ND_NOT_SUPPORTED 226 | // 227 | #define ND_NOT_SUPPORTED ((HRESULT)0xC00000BBL) 228 | 229 | // 230 | // MessageId: ND_INTERNAL_ERROR 231 | // 232 | // MessageText: 233 | // 234 | // ND_INTERNAL_ERROR 235 | // 236 | #define ND_INTERNAL_ERROR ((HRESULT)0xC00000E5L) 237 | 238 | // 239 | // MessageId: ND_INVALID_PARAMETER_1 240 | // 241 | // MessageText: 242 | // 243 | // ND_INVALID_PARAMETER_1 244 | // 245 | #define ND_INVALID_PARAMETER_1 ((HRESULT)0xC00000EFL) 246 | 247 | // 248 | // MessageId: ND_INVALID_PARAMETER_2 249 | // 250 | // MessageText: 251 | // 252 | // ND_INVALID_PARAMETER_2 253 | // 254 | #define ND_INVALID_PARAMETER_2 ((HRESULT)0xC00000F0L) 255 | 256 | // 257 | // MessageId: ND_INVALID_PARAMETER_3 258 | // 259 | // MessageText: 260 | // 261 | // ND_INVALID_PARAMETER_3 262 | // 263 | #define ND_INVALID_PARAMETER_3 ((HRESULT)0xC00000F1L) 264 | 265 | // 266 | // MessageId: ND_INVALID_PARAMETER_4 267 | // 268 | // MessageText: 269 | // 270 | // ND_INVALID_PARAMETER_4 271 | // 272 | #define ND_INVALID_PARAMETER_4 ((HRESULT)0xC00000F2L) 273 | 274 | // 275 | // MessageId: ND_INVALID_PARAMETER_5 276 | // 277 | // MessageText: 278 | // 279 | // ND_INVALID_PARAMETER_5 280 | // 281 | #define ND_INVALID_PARAMETER_5 ((HRESULT)0xC00000F3L) 282 | 283 | // 284 | // MessageId: ND_INVALID_PARAMETER_6 285 | // 286 | // MessageText: 287 | // 288 | // ND_INVALID_PARAMETER_6 289 | // 290 | #define ND_INVALID_PARAMETER_6 ((HRESULT)0xC00000F4L) 291 | 292 | // 293 | // MessageId: ND_INVALID_PARAMETER_7 294 | // 295 | // MessageText: 296 | // 297 | // ND_INVALID_PARAMETER_7 298 | // 299 | #define ND_INVALID_PARAMETER_7 ((HRESULT)0xC00000F5L) 300 | 301 | // 302 | // MessageId: ND_INVALID_PARAMETER_8 303 | // 304 | // MessageText: 305 | // 306 | // ND_INVALID_PARAMETER_8 307 | // 308 | #define ND_INVALID_PARAMETER_8 ((HRESULT)0xC00000F6L) 309 | 310 | // 311 | // MessageId: ND_INVALID_PARAMETER_9 312 | // 313 | // MessageText: 314 | // 315 | // ND_INVALID_PARAMETER_9 316 | // 317 | #define ND_INVALID_PARAMETER_9 ((HRESULT)0xC00000F7L) 318 | 319 | // 320 | // MessageId: ND_INVALID_PARAMETER_10 321 | // 322 | // MessageText: 323 | // 324 | // ND_INVALID_PARAMETER_10 325 | // 326 | #define ND_INVALID_PARAMETER_10 ((HRESULT)0xC00000F8L) 327 | 328 | // 329 | // MessageId: ND_CANCELED 330 | // 331 | // MessageText: 332 | // 333 | // ND_CANCELED 334 | // 335 | #define ND_CANCELED ((HRESULT)0xC0000120L) 336 | 337 | // 338 | // MessageId: ND_REMOTE_ERROR 339 | // 340 | // MessageText: 341 | // 342 | // ND_REMOTE_ERROR 343 | // 344 | #define ND_REMOTE_ERROR ((HRESULT)0xC000013DL) 345 | 346 | // 347 | // MessageId: ND_INVALID_ADDRESS 348 | // 349 | // MessageText: 350 | // 351 | // ND_INVALID_ADDRESS 352 | // 353 | #define ND_INVALID_ADDRESS ((HRESULT)0xC0000141L) 354 | 355 | // 356 | // MessageId: ND_INVALID_DEVICE_STATE 357 | // 358 | // MessageText: 359 | // 360 | // ND_INVALID_DEVICE_STATE 361 | // 362 | #define ND_INVALID_DEVICE_STATE ((HRESULT)0xC0000184L) 363 | 364 | // 365 | // MessageId: ND_INVALID_BUFFER_SIZE 366 | // 367 | // MessageText: 368 | // 369 | // ND_INVALID_BUFFER_SIZE 370 | // 371 | #define ND_INVALID_BUFFER_SIZE ((HRESULT)0xC0000206L) 372 | 373 | // 374 | // MessageId: ND_TOO_MANY_ADDRESSES 375 | // 376 | // MessageText: 377 | // 378 | // ND_TOO_MANY_ADDRESSES 379 | // 380 | #define ND_TOO_MANY_ADDRESSES ((HRESULT)0xC0000209L) 381 | 382 | // 383 | // MessageId: ND_ADDRESS_ALREADY_EXISTS 384 | // 385 | // MessageText: 386 | // 387 | // ND_ADDRESS_ALREADY_EXISTS 388 | // 389 | #define ND_ADDRESS_ALREADY_EXISTS ((HRESULT)0xC000020AL) 390 | 391 | // 392 | // MessageId: ND_CONNECTION_REFUSED 393 | // 394 | // MessageText: 395 | // 396 | // ND_CONNECTION_REFUSED 397 | // 398 | #define ND_CONNECTION_REFUSED ((HRESULT)0xC0000236L) 399 | 400 | // 401 | // MessageId: ND_CONNECTION_INVALID 402 | // 403 | // MessageText: 404 | // 405 | // ND_CONNECTION_INVALID 406 | // 407 | #define ND_CONNECTION_INVALID ((HRESULT)0xC000023AL) 408 | 409 | // 410 | // MessageId: ND_CONNECTION_ACTIVE 411 | // 412 | // MessageText: 413 | // 414 | // ND_CONNECTION_ACTIVE 415 | // 416 | #define ND_CONNECTION_ACTIVE ((HRESULT)0xC000023BL) 417 | 418 | // 419 | // MessageId: ND_NETWORK_UNREACHABLE 420 | // 421 | // MessageText: 422 | // 423 | // ND_NETWORK_UNREACHABLE 424 | // 425 | #define ND_NETWORK_UNREACHABLE ((HRESULT)0xC000023CL) 426 | 427 | // 428 | // MessageId: ND_HOST_UNREACHABLE 429 | // 430 | // MessageText: 431 | // 432 | // ND_HOST_UNREACHABLE 433 | // 434 | #define ND_HOST_UNREACHABLE ((HRESULT)0xC000023DL) 435 | 436 | // 437 | // MessageId: ND_CONNECTION_ABORTED 438 | // 439 | // MessageText: 440 | // 441 | // ND_CONNECTION_ABORTED 442 | // 443 | #define ND_CONNECTION_ABORTED ((HRESULT)0xC0000241L) 444 | 445 | // 446 | // MessageId: ND_DEVICE_REMOVED 447 | // 448 | // MessageText: 449 | // 450 | // ND_DEVICE_REMOVED 451 | // 452 | #define ND_DEVICE_REMOVED ((HRESULT)0xC00002B6L) 453 | 454 | #endif // _NDSTATUS_ 455 | -------------------------------------------------------------------------------- /src/ndv2lib/ndv2helper.cpp: -------------------------------------------------------------------------------- 1 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 2 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 3 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 4 | // PARTICULAR PURPOSE. 5 | // 6 | // Copyright (c) Microsoft Corporation. All rights reserved. 7 | // 8 | 9 | #pragma warning (disable:6001) 10 | #pragma warning (disable:6101) 11 | #pragma warning (disable:25006) 12 | 13 | #include 14 | #include 15 | #include 16 | #include "initguid.h" 17 | #include "ndsupport.h" 18 | 19 | 20 | typedef HRESULT 21 | (*DLLGETCLASSOBJECT)( 22 | REFCLSID rclsid, 23 | REFIID rrid, 24 | LPVOID* ppv 25 | ); 26 | 27 | typedef HRESULT 28 | (*DLLCANUNLOADNOW)(void); 29 | 30 | 31 | HMODULE g_hProvider = nullptr; 32 | IND2Provider* g_pIProvider = nullptr; 33 | DLLCANUNLOADNOW g_pfnDllCanUnloadNow = nullptr; 34 | 35 | 36 | static wchar_t* GetProviderPath( WSAPROTOCOL_INFOW* pProtocol ) 37 | { 38 | INT pathLen; 39 | INT ret, err; 40 | wchar_t* pPath; 41 | wchar_t* pPathEx; 42 | 43 | // Get the path length for the provider DLL. 44 | pathLen = 0; 45 | ret = ::WSCGetProviderPath( &pProtocol->ProviderId, nullptr, &pathLen, &err ); 46 | 47 | if( err != WSAEFAULT || pathLen == 0 ) 48 | { 49 | return nullptr; 50 | } 51 | 52 | pPath = static_cast( 53 | ::HeapAlloc( ::GetProcessHeap(), 0, sizeof(wchar_t) * pathLen ) 54 | ); 55 | if( pPath == nullptr ) 56 | { 57 | return nullptr; 58 | } 59 | 60 | ret = ::WSCGetProviderPath( &pProtocol->ProviderId, pPath, &pathLen, &err ); 61 | if( ret != 0 ) 62 | { 63 | ::HeapFree( ::GetProcessHeap(), 0, pPath ); 64 | return nullptr; 65 | } 66 | 67 | pathLen = ::ExpandEnvironmentStringsW( pPath, nullptr, 0 ); 68 | if( pathLen == 0 ) 69 | { 70 | ::HeapFree( ::GetProcessHeap(), 0, pPath ); 71 | return nullptr; 72 | } 73 | 74 | pPathEx = static_cast( 75 | ::HeapAlloc( ::GetProcessHeap(), 0, sizeof(wchar_t) * pathLen ) 76 | ); 77 | if( pPathEx == nullptr ) 78 | { 79 | ::HeapFree( ::GetProcessHeap(), 0, pPath ); 80 | return nullptr; 81 | } 82 | 83 | ret = ::ExpandEnvironmentStringsW( pPath, pPathEx, pathLen ); 84 | 85 | // We don't need the un-expanded path anymore. 86 | ::HeapFree( ::GetProcessHeap(), 0, pPath ); 87 | 88 | if( ret != pathLen ) 89 | { 90 | ::HeapFree( ::GetProcessHeap(), 0, pPathEx ); 91 | return nullptr; 92 | } 93 | 94 | return pPathEx; 95 | } 96 | 97 | static const GUID ND_V2_PROVIDER_GUID = {0xb324ac22, 0x3a56, 0x4e6f, {0xa9, 0xc4, 0x36, 0xdc, 0xc4, 0x28, 0xef, 0x65} }; 98 | static HRESULT LoadProvider( 99 | WSAPROTOCOL_INFOW* pProtocol, 100 | _In_ REFIID iid 101 | ) 102 | { 103 | wchar_t* pPath = ::GetProviderPath( pProtocol ); 104 | if( pPath == nullptr ) 105 | { 106 | return ND_UNSUCCESSFUL; 107 | } 108 | 109 | g_hProvider = ::LoadLibraryW( pPath ); 110 | 111 | ::HeapFree( ::GetProcessHeap(), 0, pPath ); 112 | 113 | if( g_hProvider == nullptr ) 114 | { 115 | return HRESULT_FROM_WIN32( ::GetLastError() ); 116 | } 117 | 118 | DLLGETCLASSOBJECT pfnDllGetClassObject = reinterpret_cast( 119 | ::GetProcAddress( g_hProvider, "DllGetClassObject" ) 120 | ); 121 | if( pfnDllGetClassObject == nullptr ) 122 | { 123 | return HRESULT_FROM_WIN32( ::GetLastError() ); 124 | } 125 | 126 | g_pfnDllCanUnloadNow = reinterpret_cast( 127 | ::GetProcAddress( g_hProvider, "DllCanUnloadNow" ) 128 | ); 129 | if( g_pfnDllCanUnloadNow == nullptr ) 130 | { 131 | return HRESULT_FROM_WIN32( ::GetLastError() ); 132 | } 133 | 134 | IClassFactory* pClassFactory; 135 | HRESULT hr = pfnDllGetClassObject( 136 | pProtocol->ProviderId, 137 | IID_IClassFactory, 138 | reinterpret_cast(&pClassFactory) 139 | ); 140 | if( FAILED(hr) ) 141 | { 142 | return hr; 143 | } 144 | 145 | hr = pClassFactory->CreateInstance( 146 | nullptr, 147 | iid, 148 | reinterpret_cast(&g_pIProvider) 149 | ); 150 | 151 | // Now that we asked for the provider, we don't need the class factory. 152 | pClassFactory->Release(); 153 | return hr; 154 | } 155 | 156 | 157 | static HRESULT Init() 158 | { 159 | // Enumerate the provider catalog, find the first ND provider and load it. 160 | DWORD len = 0; 161 | INT err; 162 | INT ret = ::WSCEnumProtocols( nullptr, nullptr, &len, &err ); 163 | if( ret != SOCKET_ERROR || err != WSAENOBUFS ) 164 | { 165 | return ND_INTERNAL_ERROR; 166 | } 167 | 168 | WSAPROTOCOL_INFOW* pProtocols = static_cast( 169 | ::HeapAlloc( ::GetProcessHeap(), 0, len ) 170 | ); 171 | if( pProtocols == nullptr ) 172 | { 173 | return ND_NO_MEMORY; 174 | } 175 | 176 | ret = ::WSCEnumProtocols( nullptr, pProtocols, &len, &err ); 177 | if( ret == SOCKET_ERROR ) 178 | { 179 | ::HeapFree( ::GetProcessHeap(), 0, pProtocols ); 180 | return ND_INTERNAL_ERROR; 181 | } 182 | 183 | HRESULT hr = ND_NOT_SUPPORTED; 184 | for( DWORD i = 0; i < len / sizeof(WSAPROTOCOL_INFOW); i++ ) 185 | { 186 | #define ServiceFlags1Flags (XP1_GUARANTEED_DELIVERY | XP1_GUARANTEED_ORDER | \ 187 | XP1_MESSAGE_ORIENTED | XP1_CONNECT_DATA) 188 | 189 | if( (pProtocols[i].dwServiceFlags1 & ServiceFlags1Flags) != 190 | ServiceFlags1Flags ) 191 | { 192 | continue; 193 | } 194 | 195 | if( pProtocols[i].iAddressFamily != AF_INET && 196 | pProtocols[i].iAddressFamily != AF_INET6 ) 197 | { 198 | continue; 199 | } 200 | 201 | if( pProtocols[i].iSocketType != -1 ) 202 | { 203 | continue; 204 | } 205 | 206 | if( pProtocols[i].iProtocol != 0 ) 207 | { 208 | continue; 209 | } 210 | 211 | if( pProtocols[i].iProtocolMaxOffset != 0 ) 212 | { 213 | continue; 214 | } 215 | 216 | if( pProtocols[i].ProviderId != ND_V2_PROVIDER_GUID ) 217 | { 218 | continue; 219 | } 220 | 221 | hr = ::LoadProvider( &pProtocols[i] , IID_IND2Provider); 222 | } 223 | ::HeapFree( ::GetProcessHeap(), 0, pProtocols ); 224 | 225 | return hr; 226 | } 227 | 228 | 229 | EXTERN_C HRESULT ND_HELPER_API 230 | NdStartup( 231 | VOID 232 | ) 233 | { 234 | int ret; 235 | WSADATA data; 236 | 237 | ret = ::WSAStartup( MAKEWORD(2, 2), &data ); 238 | if( ret != 0 ) 239 | { 240 | return HRESULT_FROM_WIN32( ret ); 241 | } 242 | 243 | HRESULT hr = Init(); 244 | if( FAILED( hr ) ) 245 | { 246 | NdCleanup(); 247 | } 248 | 249 | return hr; 250 | } 251 | 252 | 253 | EXTERN_C HRESULT ND_HELPER_API 254 | NdCleanup( 255 | VOID 256 | ) 257 | { 258 | if( g_pIProvider != nullptr ) 259 | { 260 | g_pIProvider->Release(); 261 | g_pIProvider = nullptr; 262 | } 263 | 264 | if( g_hProvider != nullptr ) 265 | { 266 | ::FreeLibrary( g_hProvider ); 267 | g_hProvider = nullptr; 268 | } 269 | 270 | ::WSACleanup(); 271 | 272 | return S_OK; 273 | } 274 | 275 | 276 | EXTERN_C VOID ND_HELPER_API 277 | NdFlushProviders( 278 | VOID 279 | ) 280 | { 281 | return; 282 | } 283 | 284 | 285 | EXTERN_C HRESULT ND_HELPER_API 286 | NdQueryAddressList( 287 | _In_ DWORD Flags, 288 | _Out_opt_bytecap_post_bytecount_(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList, 289 | _Inout_ SIZE_T* pcbAddressList 290 | ) 291 | { 292 | UNREFERENCED_PARAMETER( Flags ); 293 | 294 | if( g_pIProvider == nullptr ) 295 | { 296 | return ND_DEVICE_NOT_READY; 297 | } 298 | 299 | return g_pIProvider->QueryAddressList( pAddressList, (ULONG*)pcbAddressList ); 300 | } 301 | 302 | 303 | EXTERN_C HRESULT ND_HELPER_API 304 | NdResolveAddress( 305 | _In_bytecount_(cbRemoteAddress) const struct sockaddr* pRemoteAddress, 306 | _In_ SIZE_T cbRemoteAddress, 307 | _Out_bytecap_(*pcbLocalAddress) struct sockaddr* pLocalAddress, 308 | _Inout_ SIZE_T* pcbLocalAddress 309 | ) 310 | { 311 | SIZE_T len; 312 | 313 | // 314 | // Cap to max DWORD value. This has the added benefit of zeroing the upper 315 | // bits on 64-bit platforms, so that the returned value is correct. 316 | // 317 | if( *pcbLocalAddress > UINT_MAX ) 318 | { 319 | *pcbLocalAddress = UINT_MAX; 320 | } 321 | 322 | // We store the original length so we can distinguish from different 323 | // errors that return WSAEFAULT. 324 | len = *pcbLocalAddress; 325 | 326 | // Create a socket for address changes. 327 | SOCKET s = ::WSASocket( AF_INET, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED ); 328 | if( s == INVALID_SOCKET ) 329 | { 330 | return ND_INSUFFICIENT_RESOURCES; 331 | } 332 | 333 | int ret = ::WSAIoctl( 334 | s, 335 | SIO_ROUTING_INTERFACE_QUERY, 336 | const_cast(pRemoteAddress), 337 | static_cast(cbRemoteAddress), 338 | pLocalAddress, 339 | static_cast(len), 340 | reinterpret_cast(pcbLocalAddress), 341 | nullptr, 342 | nullptr 343 | ); 344 | 345 | if( ret == SOCKET_ERROR ) 346 | { 347 | switch( ::GetLastError() ) 348 | { 349 | case WSAEFAULT: 350 | if( len < *pcbLocalAddress ) 351 | { 352 | return ND_BUFFER_OVERFLOW; 353 | } 354 | 355 | __fallthrough; 356 | default: 357 | return ND_UNSUCCESSFUL; 358 | case WSAEINVAL: 359 | return ND_INVALID_ADDRESS; 360 | case WSAENETUNREACH: 361 | case WSAENETDOWN: 362 | return ND_NETWORK_UNREACHABLE; 363 | } 364 | } 365 | 366 | return ND_SUCCESS; 367 | } 368 | 369 | 370 | EXTERN_C HRESULT ND_HELPER_API 371 | NdCheckAddress( 372 | _In_bytecount_(cbAddress) const struct sockaddr* pAddress, 373 | _In_ SIZE_T cbAddress 374 | ) 375 | { 376 | INDAdapter* pIAdapter; 377 | 378 | HRESULT hr = NdOpenV1Adapter( pAddress, cbAddress, &pIAdapter ); 379 | if( SUCCEEDED( hr ) ) 380 | { 381 | pIAdapter->Release(); 382 | } 383 | return hr; 384 | } 385 | 386 | 387 | EXTERN_C HRESULT ND_HELPER_API 388 | NdOpenAdapter( 389 | _In_ REFIID /*iid*/, 390 | _In_bytecount_(cbAddress) const struct sockaddr* pAddress, 391 | _In_ SIZE_T cbAddress, 392 | _Deref_out_ VOID** ppIAdapter 393 | ) 394 | { 395 | if( g_pIProvider == nullptr ) 396 | { 397 | return ND_DEVICE_NOT_READY; 398 | } 399 | UINT64 uAdapterId; 400 | 401 | HRESULT hr = g_pIProvider->ResolveAddress(pAddress, (ULONG) cbAddress, &uAdapterId); 402 | 403 | if( FAILED(hr)) 404 | { 405 | 406 | return ND_UNSUCCESSFUL; 407 | } 408 | 409 | return g_pIProvider->OpenAdapter( IID_IND2Adapter, uAdapterId, ppIAdapter ); 410 | } 411 | 412 | 413 | EXTERN_C HRESULT ND_HELPER_API 414 | NdOpenV1Adapter( 415 | /*_In_bytecount_(cbAddress)*/ const struct sockaddr* /*pAddress*/, 416 | _In_ SIZE_T /*cbAddress*/, 417 | _Deref_out_ INDAdapter** /*ppIAdapter*/ 418 | ) 419 | { 420 | if( g_pIProvider == nullptr ) 421 | { 422 | return ND_DEVICE_NOT_READY; 423 | } 424 | 425 | return S_OK; 426 | // return g_pIProvider->OpenAdapter( pAddress, cbAddress, ppIAdapter ); 427 | } 428 | 429 | -------------------------------------------------------------------------------- /src/Pingpong/Pingpong.cpp: -------------------------------------------------------------------------------- 1 | // Pingpong.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace hermes; 14 | 15 | const uint16_t x_DefaultPort = 54325; 16 | const uint64_t x_MaxXfer = (4 * 1024 * 1024); 17 | const uint64_t x_HdrLen = 40; 18 | const size_t x_MaxVolume = (500 * x_MaxXfer); 19 | const uint64_t x_MaxIterations = 100000; 20 | const size_t x_MaxMsgSize = 8 * 1024 * 1024; // 4MB 21 | 22 | #define RECV 0 23 | #define SEND 1 24 | 25 | 26 | void ShowUsage() 27 | { 28 | printf("Run as server: pingpong s \n" 29 | "Run as client: pingpong c : \n" 30 | "\ts - start as server (listen on Port)\n" 31 | "\tc - start as client (connect to server IP:Port)\n" 32 | "\t - IPv4 Address, only needed in client\n" 33 | "\t - Port number" 34 | "\t - size of the test message, in kilo-byte" 35 | "\t - Number of round trips to run" 36 | ); 37 | } 38 | 39 | std::unique_ptr g_pHermes; 40 | auto g_connection = HSocketHandle(INVALID_HANDLE_VALUE); 41 | auto g_numTests = 1'000'000ull; 42 | auto g_MsgSize = 0ull; 43 | 44 | std::chrono::time_point g_start, g_end; 45 | char g_msg[x_MaxMsgSize]; 46 | 47 | 48 | // Used by echo server, reclaim the buffer used to send message 49 | // 50 | class OnEchoFinish : public SendCompletionNotifier 51 | { 52 | void operator() ( 53 | // Indicate result of the send operation 54 | StatusCode status, 55 | 56 | // parameters provided to the original send operation 57 | _In_ void* sndContext, 58 | _In_ const gsl::span buf 59 | ) override 60 | { 61 | auto pBuf = reinterpret_cast(sndContext); 62 | if (pBuf->GetData().data() != buf.data()) 63 | { 64 | std::cerr << "OnSent parameter error!" << std::endl; 65 | std::terminate(); 66 | } 67 | pBuf->Dispose(); 68 | pBuf = nullptr; 69 | } 70 | } g_onEchoFinish; 71 | 72 | 73 | // Used by client 74 | class OnSent : public SendCompletionNotifier 75 | { 76 | public: 77 | void operator() ( 78 | // Indicate result of the send operation 79 | StatusCode status, 80 | 81 | // parameters provided to the original send operation 82 | _In_ void* sndContext, 83 | _In_ const gsl::span buf 84 | ) override 85 | { 86 | if (sndContext != nullptr) 87 | { 88 | std::cerr << "Unexpected context!" << std::endl; 89 | std::terminate(); 90 | } 91 | } 92 | } g_onSent; 93 | 94 | 95 | class OnConnect: public ConnectionNotifier 96 | { 97 | public: 98 | void operator() ( 99 | // Socket that holds the new connection 100 | _In_ HSocketHandle pSocket, 101 | 102 | StatusCode status 103 | ) override 104 | { 105 | std::cout << "Socket connected!" << std::endl; 106 | if (status != H_ok) { 107 | std::cerr << "Socket closed: " << std::hex << status << std::dec << std::endl; 108 | std::exit(0); 109 | } 110 | 111 | g_connection = pSocket; 112 | 113 | } 114 | } g_onConnect; 115 | 116 | 117 | class ClientConnected : public ConnectionNotifier 118 | { 119 | public: 120 | void operator() 121 | ( 122 | // Socket that holds the new connection 123 | _In_ HSocketHandle pSocket, 124 | 125 | StatusCode status 126 | ) override 127 | { 128 | std::cout << "Socket connected!" << std::endl; 129 | if (status != H_ok) { 130 | std::cerr << "client connection closed: " << std::hex << status << std::dec << std::endl; 131 | std::exit(0); 132 | } 133 | 134 | if (g_connection != pSocket) 135 | { 136 | std::cerr << "Socket failure" << std::endl; 137 | std::terminate(); 138 | } 139 | 140 | auto cv = '!'; 141 | for (auto& c : g_msg) { 142 | c = cv++; 143 | if (cv > '}') 144 | cv = '!'; 145 | } 146 | g_msg[g_MsgSize - 1] = '\0'; 147 | 148 | auto buf = gsl::span(reinterpret_cast(g_msg), g_MsgSize); 149 | g_start = std::chrono::high_resolution_clock::now(); 150 | g_pHermes->Send(pSocket, nullptr, buf, g_onSent); 151 | } 152 | } g_clientConnected; 153 | 154 | 155 | class OnServerReceive: public RcvNotifier 156 | { 157 | 158 | public: 159 | OnServerReceive() 160 | {} 161 | 162 | void operator() ( 163 | // Socket that holds the connection 164 | HSocketHandle pSocket, 165 | 166 | // An reclaimable buffer that contains the message 167 | // User must call pBuf->Dispose() to release it 168 | // after finished processing the message. 169 | // 170 | _In_ mbuf::DisposableBuffer* pBuf, 171 | 172 | StatusCode status 173 | ) override 174 | { 175 | //std::cout << "Socket Received! " << g_numTests << std::endl; 176 | if (status != H_ok) { 177 | std::cerr << "Failure in server receive: " << status << std::endl; 178 | std::terminate(); 179 | } 180 | 181 | g_pHermes->Send(pSocket, pBuf, pBuf->GetData(), g_onEchoFinish); 182 | g_numTests++; 183 | } 184 | } g_serverReceived; 185 | 186 | 187 | class OnClientReceive : public RcvNotifier 188 | { 189 | public: 190 | OnClientReceive() 191 | { } 192 | 193 | void operator() ( 194 | // Socket that holds the connection 195 | HSocketHandle pSocket, 196 | 197 | // An reclaimable buffer that contains the message 198 | // User must call pBuf->Dispose() to release it 199 | // after finished processing the message. 200 | // 201 | _In_ mbuf::DisposableBuffer* pBuf, 202 | 203 | StatusCode status 204 | ) override 205 | { 206 | //std::cout << "Socket Received! " << g_numTests << std::endl; 207 | if (status != H_ok) { 208 | std::cerr << "Failed to create server socket: " << status << std::endl; 209 | std::terminate(); 210 | } 211 | 212 | g_numTests--; 213 | if (g_numTests > 0) 214 | { 215 | gsl::span buf = gsl::span(reinterpret_cast(g_msg), g_MsgSize); 216 | g_pHermes->Send(pSocket, nullptr, buf, g_onSent); 217 | } 218 | else { 219 | g_end = std::chrono::high_resolution_clock::now(); 220 | std::chrono::duration elapsed_seconds = g_end - g_start; 221 | std::cout << "Elapsed time: " << elapsed_seconds.count() << std::endl; 222 | } 223 | pBuf->Dispose(); 224 | 225 | } 226 | } g_clientReceived; 227 | 228 | 229 | 230 | // Server side of the test, listen on a port, accept one connection, and echo 231 | // all received messages. 232 | // 233 | void Server(uint16_t port) 234 | { 235 | 236 | StatusCode err; 237 | auto serverSock = g_pHermes->CreateSocket(err); 238 | 239 | if (err != H_ok) { 240 | std::cerr << "Failed to create server socket: " << err << std::endl; 241 | std::terminate(); 242 | } 243 | 244 | err = g_pHermes->Listen(serverSock, port); 245 | if (err != H_ok) { 246 | std::cerr << "Failed to listen on designated port" << err << std::endl; 247 | std::terminate(); 248 | } 249 | 250 | std::cout << "Echo Server Listens on port: " << g_pHermes->GetHomePort(serverSock) << std::endl; 251 | 252 | err = g_pHermes->Accept(serverSock, g_onConnect, g_serverReceived); 253 | if (err != H_ok) { 254 | std::cerr << "Failed to accept new connection: " << err << std::endl; 255 | std::terminate(); 256 | } 257 | 258 | while (true) 259 | { 260 | std::cout << "Number of tests: " << g_numTests << std::endl; 261 | Sleep(10000); 262 | } 263 | 264 | } 265 | 266 | 267 | // Client side of the test, connect to server, and send the first 268 | // message, reply to messages from server. 269 | // 270 | void Client(uint32_t ip, uint16_t port) 271 | { 272 | StatusCode err; 273 | g_connection = g_pHermes->CreateSocket(err); 274 | if (err != H_ok) { 275 | std::cerr << "Failed to create server socket: " << err << std::endl; 276 | std::terminate(); 277 | } 278 | 279 | err = g_pHermes->Connect(g_connection, ip, port, g_clientConnected, g_clientReceived); 280 | if (err != H_ok) { 281 | std::cerr << "Failed to connect: " << err << std::endl; 282 | std::terminate(); 283 | } 284 | 285 | while (g_numTests > 0) 286 | { 287 | std::cout << "Number of tests: " << g_numTests << std::endl; 288 | Sleep(10000); 289 | } 290 | 291 | } 292 | 293 | int __cdecl _tmain(int argc, TCHAR* argv[]) 294 | { 295 | g_pHermes = hermes::HermesFixedRIOFactory(size_t(512 * 1024), uint32_t(32)); 296 | bool bServer = false; 297 | bool bClient = false; 298 | struct sockaddr_in v4Server = { 0 }; 299 | int port = 0; 300 | 301 | for (int i = 1; i < argc; i++) 302 | { 303 | const TCHAR* pArg; 304 | int len; 305 | 306 | pArg = argv[i]; 307 | 308 | // Skip leading dashes/slashes 309 | while (*pArg == '-' || *pArg == '/') 310 | { 311 | pArg++; 312 | } 313 | 314 | switch (*pArg) 315 | { 316 | case _T('s'): 317 | case _T('S'): 318 | bServer = true; 319 | if (++i == argc) 320 | { 321 | break; 322 | } 323 | 324 | port = _wtoi(argv[i]); 325 | if (port == 0) 326 | { 327 | port = x_DefaultPort; 328 | } 329 | 330 | break; 331 | case _T('c'): 332 | case _T('C'): 333 | bClient = true; 334 | if (++i == argc) 335 | { 336 | fprintf_s(stderr, "Missing Parameter: :"); 337 | ShowUsage(); 338 | exit(-1); 339 | } 340 | 341 | len = sizeof(v4Server); 342 | WSAStringToAddress( 343 | argv[i], 344 | AF_INET, 345 | NULL, 346 | reinterpret_cast(&v4Server), 347 | &len 348 | ); 349 | 350 | if (++i == argc) 351 | { 352 | fprintf_s(stderr, "Missing Parameter: "); 353 | ShowUsage(); 354 | exit(-1); 355 | } 356 | g_MsgSize = _wtoi(argv[i]) * 1024; 357 | if (0 == g_MsgSize) 358 | { 359 | fprintf_s(stderr, "Invalid Parameter: "); 360 | ShowUsage(); 361 | exit(-1); 362 | } 363 | if (g_MsgSize > x_MaxMsgSize) 364 | { 365 | fprintf_s(stderr, "Message size too big: max value 4MB."); 366 | ShowUsage(); 367 | exit(-1); 368 | } 369 | 370 | if (++i == argc) 371 | { 372 | fprintf_s(stderr, "Missing parameter: !"); 373 | ShowUsage(); 374 | exit(-1); 375 | } 376 | g_numTests = _wtoi(argv[i]); 377 | break; 378 | 379 | default: 380 | _tprintf(_T("Unknown parameter %s\n"), pArg); 381 | ShowUsage(); 382 | exit(__LINE__); 383 | } 384 | } 385 | if ((bClient && bServer) || (!bClient && !bServer)) 386 | { 387 | printf("Exactly one of client (c or " 388 | "server (s) must be specified.\n\n"); 389 | ShowUsage(); 390 | exit(__LINE__); 391 | } 392 | 393 | if (bServer) 394 | { 395 | g_numTests = 0; 396 | Server(port); 397 | } 398 | else 399 | { 400 | if (v4Server.sin_addr.S_un.S_addr == 0) 401 | { 402 | ShowUsage(); 403 | exit(-1); 404 | } 405 | if (v4Server.sin_port == 0) 406 | { 407 | v4Server.sin_port = htons(x_DefaultPort); 408 | } 409 | Client(ntohl(v4Server.sin_addr.S_un.S_addr), ntohs(v4Server.sin_port)); 410 | } 411 | 412 | return 0; 413 | } 414 | 415 | -------------------------------------------------------------------------------- /src/ndv2lib/ndioctl.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Module Name: 6 | 7 | ndioctl.h 8 | 9 | Abstract: 10 | 11 | NetworkDirect Service Provider IOCTL definitions 12 | 13 | Environment: 14 | 15 | User mode and kernel mode 16 | 17 | --*/ 18 | 19 | #ifndef _NDIOCTL_H_ 20 | #define _NDIOCTL_H_ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "nddef.h" 29 | 30 | #define ND_IOCTL_VERSION 1 31 | 32 | #pragma warning(push) 33 | #pragma warning(disable:4201) 34 | 35 | typedef enum _ND_MAPPING_TYPE { 36 | NdMapIoSpace, 37 | NdMapMemory, 38 | NdMapMemoryCoallesce, 39 | NdMapPages, 40 | NdMapPagesCoallesce, 41 | NdUnmapIoSpace, 42 | NdUnmapMemory, 43 | NdMaximumMapType 44 | } ND_MAPPING_TYPE; 45 | 46 | typedef enum _ND_CACHING_TYPE { 47 | NdNonCached = 0, // MmNonCached 48 | NdCached = 1, // MmCached 49 | NdWriteCombined = 2,// MmWriteCombined 50 | NdMaximumCacheType 51 | } ND_CACHING_TYPE; 52 | 53 | typedef enum _ND_ACCESS_TYPE { 54 | NdReadAccess = 0, // IoReadAccess 55 | NdWriteAccess = 1, // IoWriteAccess 56 | NdModifyAccess = 2 // IoModifyAccess 57 | } ND_ACCESS_TYPE; 58 | 59 | typedef struct _ND_MAP_IO_SPACE { 60 | ND_MAPPING_TYPE MapType; 61 | ND_CACHING_TYPE CacheType; 62 | ULONG CbLength; 63 | } ND_MAP_IO_SPACE; 64 | 65 | typedef struct _ND_MAP_MEMORY { 66 | ND_MAPPING_TYPE MapType; 67 | ND_ACCESS_TYPE AccessType; 68 | UINT64 Address; 69 | ULONG CbLength; 70 | } ND_MAP_MEMORY; 71 | 72 | typedef struct _ND_MAPPING_ID { 73 | ND_MAPPING_TYPE MapType; 74 | UINT64 Id; 75 | } ND_MAPPING_ID; 76 | 77 | typedef struct _NDK_MAP_PAGES { 78 | ND_MAP_MEMORY Header; 79 | ULONG CbLogicalPageAddressesOffset; 80 | } NDK_MAP_PAGES; 81 | 82 | typedef union _ND_MAPPING { 83 | ND_MAPPING_TYPE MapType; 84 | ND_MAP_IO_SPACE MapIoSpace; 85 | ND_MAP_MEMORY MapMemory; 86 | ND_MAPPING_ID MappingId; 87 | NDK_MAP_PAGES MapPages; 88 | } ND_MAPPING; 89 | 90 | typedef struct _ND_MAPPING_RESULT { 91 | UINT64 Id; 92 | UINT64 Information; 93 | } ND_MAPPING_RESULT; 94 | 95 | typedef struct _ND_RESOURCE_DESCRIPTOR { 96 | UINT64 Handle; 97 | ULONG CeMappingResults; 98 | ULONG CbMappingResultsOffset; 99 | } ND_RESOURCE_DESCRIPTOR; 100 | 101 | typedef struct _ND_HANDLE { 102 | ULONG Version; 103 | ULONG Reserved; 104 | UINT64 Handle; 105 | } ND_HANDLE; 106 | 107 | typedef struct _ND_RESOLVE_ADDRESS { 108 | ULONG Version; 109 | ULONG Reserved; 110 | SOCKADDR_INET Address; 111 | } ND_RESOLVE_ADDRESS; 112 | 113 | typedef struct _ND_OPEN_ADAPTER { 114 | ULONG Version; 115 | ULONG Reserved; 116 | ULONG CeMappingCount; 117 | ULONG CbMappingsOffset; 118 | UINT64 AdapterId; 119 | } ND_OPEN_ADAPTER; 120 | 121 | typedef struct _ND_ADAPTER_QUERY { 122 | ULONG Version; 123 | ULONG InfoVersion; 124 | UINT64 AdapterHandle; 125 | } ND_ADAPTER_QUERY; 126 | 127 | typedef struct _ND_CREATE_CQ { 128 | ULONG Version; 129 | ULONG QueueDepth; 130 | ULONG CeMappingCount; 131 | ULONG CbMappingsOffset; 132 | UINT64 AdapterHandle; 133 | GROUP_AFFINITY Affinity; 134 | } ND_CREATE_CQ; 135 | 136 | typedef struct _ND_CREATE_SRQ { 137 | ULONG Version; 138 | ULONG QueueDepth; 139 | ULONG CeMappingCount; 140 | ULONG CbMappingsOffset; 141 | ULONG MaxRequestSge; 142 | ULONG NotifyThreshold; 143 | UINT64 PdHandle; 144 | GROUP_AFFINITY Affinity; 145 | } ND_CREATE_SRQ; 146 | 147 | typedef struct _ND_CREATE_QP_HDR { 148 | ULONG Version; 149 | ULONG CbMaxInlineData; 150 | ULONG CeMappingCount; 151 | ULONG CbMappingsOffset; 152 | ULONG InitiatorQueueDepth; 153 | ULONG MaxInitiatorRequestSge; 154 | UINT64 ReceiveCqHandle; 155 | UINT64 InitiatorCqHandle; 156 | UINT64 PdHandle; 157 | } ND_CREATE_QP_HDR; 158 | 159 | typedef struct _ND_CREATE_QP { 160 | ND_CREATE_QP_HDR Header; 161 | ULONG ReceiveQueueDepth; 162 | ULONG MaxReceiveRequestSge; 163 | } ND_CREATE_QP; 164 | 165 | typedef struct _ND_CREATE_QP_WITH_SRQ { 166 | ND_CREATE_QP_HDR Header; 167 | UINT64 SrqHandle; 168 | } ND_CREATE_QP_WITH_SRQ; 169 | 170 | typedef struct _ND_SRQ_MODIFY { 171 | ULONG Version; 172 | ULONG QueueDepth; 173 | ULONG CeMappingCount; 174 | ULONG CbMappingsOffset; 175 | ULONG NotifyThreshold; 176 | ULONG Reserved; 177 | UINT64 SrqHandle; 178 | } ND_SRQ_MODIFY; 179 | 180 | typedef struct _ND_CQ_MODIFY { 181 | ULONG Version; 182 | ULONG QueueDepth; 183 | ULONG CeMappingCount; 184 | ULONG CbMappingsOffset; 185 | UINT64 CqHandle; 186 | } ND_CQ_MODIFY; 187 | 188 | typedef struct _ND_CQ_NOTIFY { 189 | ULONG Version; 190 | ULONG Type; 191 | UINT64 CqHandle; 192 | } ND_CQ_NOTIFY; 193 | 194 | typedef struct _ND_MR_REGISTER_HDR { 195 | ULONG Version; 196 | ULONG Flags; 197 | UINT64 CbLength; 198 | UINT64 TargetAddress; 199 | UINT64 MrHandle; 200 | } ND_MR_REGISTER_HDR; 201 | 202 | typedef struct _ND_MR_REGISTER { 203 | ND_MR_REGISTER_HDR Header; 204 | UINT64 Address; 205 | } ND_MR_REGISTER; 206 | 207 | typedef struct _ND_BIND { 208 | ULONG Version; 209 | ULONG Reserved; 210 | UINT64 Handle; 211 | SOCKADDR_INET Address; 212 | } ND_BIND, NDV_PARTITION_UNBIND_ADDRESS; 213 | 214 | typedef struct _ND_READ_LIMITS { 215 | ULONG Inbound; 216 | ULONG Outbound; 217 | } ND_READ_LIMITS; 218 | 219 | typedef struct _ND_CONNECT { 220 | ULONG Version; 221 | ULONG Reserved; 222 | ND_READ_LIMITS ReadLimits; 223 | ULONG CbPrivateDataLength; 224 | ULONG CbPrivateDataOffset; 225 | UINT64 ConnectorHandle; 226 | UINT64 QpHandle; 227 | SOCKADDR_INET DestinationAddress; 228 | IF_PHYSICAL_ADDRESS DestinationHwAddress; 229 | } ND_CONNECT; 230 | 231 | typedef struct _ND_ACCEPT { 232 | ULONG Version; 233 | ULONG Reserved; 234 | ND_READ_LIMITS ReadLimits; 235 | ULONG CbPrivateDataLength; 236 | ULONG CbPrivateDataOffset; 237 | UINT64 ConnectorHandle; 238 | UINT64 QpHandle; 239 | } ND_ACCEPT; 240 | 241 | typedef struct _ND_REJECT { 242 | ULONG Version; 243 | ULONG Reserved; 244 | ULONG CbPrivateDataLength; 245 | ULONG CbPrivateDataOffset; 246 | UINT64 ConnectorHandle; 247 | } ND_REJECT; 248 | 249 | typedef struct _ND_LISTEN { 250 | ULONG Version; 251 | ULONG Backlog; 252 | UINT64 ListenerHandle; 253 | } ND_LISTEN; 254 | 255 | typedef struct _ND_GET_CONNECTION_REQUEST { 256 | ULONG Version; 257 | ULONG Reserved; 258 | UINT64 ListenerHandle; 259 | UINT64 ConnectorHandle; 260 | } ND_GET_CONNECTION_REQUEST; 261 | 262 | 263 | #if defined(_DDK_DRIVER_) || defined(_NTIFS_) 264 | 265 | typedef enum _NDV_MMIO_TYPE { 266 | NdPartitionKernelVirtual, 267 | NdPartitionSystemPhysical, 268 | NdPartitionGuestPhysical, 269 | NdMaximumMmioType 270 | } NDV_MMIO_TYPE; 271 | 272 | typedef struct _NDV_RESOLVE_ADAPTER_ID { 273 | ULONG Version; 274 | IF_PHYSICAL_ADDRESS HwAddress; 275 | } NDV_RESOLVE_ADAPTER_ID; 276 | 277 | typedef struct _NDV_PARTITION_CREATE { 278 | ULONG Version; 279 | NDV_MMIO_TYPE MmioType; 280 | UINT64 AdapterId; 281 | UINT64 XmitCap; 282 | } NDV_PARTITION_CREATE; 283 | 284 | typedef struct _NDV_PARTITION_BIND_LUID { 285 | ULONG Version; 286 | ULONG Reserved; 287 | UINT64 PartitionHandle; 288 | IF_PHYSICAL_ADDRESS HwAddress; 289 | IF_LUID Luid; 290 | } NDV_PARTITION_BIND_LUID; 291 | 292 | typedef struct _NDV_PARTITION_BIND_ADDRESS { 293 | ULONG Version; 294 | ULONG Reserved; 295 | UINT64 PartitionHandle; 296 | SOCKADDR_INET Address; 297 | IF_PHYSICAL_ADDRESS GuestHwAddress; 298 | IF_PHYSICAL_ADDRESS HwAddress; 299 | } NDV_PARTITION_BIND_ADDRESS; 300 | 301 | typedef struct _NDK_MR_REGISTER { 302 | ND_MR_REGISTER_HDR Header; 303 | ULONG CbLogicalPageAddressesOffset; 304 | } NDK_MR_REGISTER; 305 | 306 | typedef struct _NDK_BIND { 307 | ND_BIND Header; 308 | LUID AuthenticationId; 309 | BOOLEAN IsAdmin; 310 | } NDK_BIND; 311 | 312 | #endif // _DDK_DRIVER_ 313 | 314 | #pragma warning(pop) 315 | 316 | #define ND_FUNCTION(r_, i_) (r_ << 6 | i_) 317 | #define IOCTL_ND(r_, i_) CTL_CODE( FILE_DEVICE_NETWORK, ND_FUNCTION(r_, i_), METHOD_BUFFERED, FILE_ANY_ACCESS ) 318 | 319 | #define ND_FUNCTION_FROM_CTL_CODE(ctrlCode_) ((ctrlCode_ >> 2) & 0xFFF) 320 | #define ND_RESOURCE_FROM_CTL_CODE(ctrlCode_) (ND_FUNCTION_FROM_CTL_CODE(ctrlCode_) >> 6) 321 | #define ND_OPERATION_FROM_CTRL_CODE(ctrlCode_) (ND_FUNCTION_FROM_CTL_CODE(ctrlCode_) & 0x3F) 322 | 323 | #define ND_DOS_DEVICE_NAME L"\\DosDevices\\Global\\NetworkDirect" 324 | #define ND_WIN32_DEVICE_NAME L"\\\\.\\NetworkDirect" 325 | 326 | typedef enum _ND_RESOURCE_TYPE { 327 | NdProvider = 0, 328 | NdAdapter = 1, 329 | NdPd = 2, 330 | NdCq = 3, 331 | NdMr = 4, 332 | NdMw = 5, 333 | NdSrq = 6, 334 | NdConnector = 7, 335 | NdListener = 8, 336 | NdQp = 9, 337 | NdVirtualPartition = 10, 338 | ND_RESOURCE_TYPE_COUNT 339 | } ND_RESOURCE_TYPE; 340 | 341 | #define ND_OPERATION_COUNT 14 342 | 343 | #define IOCTL_ND_PROVIDER(i_) IOCTL_ND(NdProvider, i_) 344 | #define IOCTL_ND_ADAPTER(i_) IOCTL_ND(NdAdapter, i_) 345 | #define IOCTL_ND_PD(i_) IOCTL_ND(NdPd, i_) 346 | #define IOCTL_ND_CQ(i_) IOCTL_ND(NdCq, i_) 347 | #define IOCTL_ND_MR(i_) IOCTL_ND(NdMr, i_) 348 | #define IOCTL_ND_MW(i_) IOCTL_ND(NdMw, i_) 349 | #define IOCTL_ND_SRQ(i_) IOCTL_ND(NdSrq, i_) 350 | #define IOCTL_ND_CONNECTOR(i_) IOCTL_ND(NdConnector, i_) 351 | #define IOCTL_ND_LISTENER(i_) IOCTL_ND(NdListener, i_) 352 | #define IOCTL_ND_QP(i_) IOCTL_ND(NdQp, i_) 353 | #define IOCTL_ND_VIRTUAL_PARTITION(i_) IOCTL_ND(NdVirtualPartition, i_) 354 | 355 | // Provider IOCTLs 356 | #define IOCTL_ND_PROVIDER_INIT IOCTL_ND_PROVIDER( 0 ) 357 | #define IOCTL_ND_PROVIDER_BIND_FILE IOCTL_ND_PROVIDER( 1 ) 358 | #define IOCTL_ND_PROVIDER_QUERY_ADDRESS_LIST IOCTL_ND_PROVIDER( 2 ) 359 | #define IOCTL_ND_PROVIDER_RESOLVE_ADDRESS IOCTL_ND_PROVIDER( 3 ) 360 | #define IOCTL_ND_PROVIDER_MAX_OPERATION 4 361 | 362 | // Adapter IOCTLs 363 | #define IOCTL_ND_ADAPTER_OPEN IOCTL_ND_ADAPTER( 0 ) 364 | #define IOCTL_ND_ADAPTER_CLOSE IOCTL_ND_ADAPTER( 1 ) 365 | #define IOCTL_ND_ADAPTER_QUERY IOCTL_ND_ADAPTER( 2 ) 366 | #define IOCTL_ND_ADAPTER_QUERY_ADDRESS_LIST IOCTL_ND_ADAPTER( 3 ) 367 | #define IOCTL_ND_ADAPTER_MAX_OPERATION 4 368 | 369 | // Protection Domain IOCTLs 370 | #define IOCTL_ND_PD_CREATE IOCTL_ND_PD( 0 ) 371 | #define IOCTL_ND_PD_FREE IOCTL_ND_PD( 1 ) 372 | #define IOCTL_ND_PD_MAX_OPERATION 2 373 | 374 | // Completion Queue IOCTLs 375 | #define IOCTL_ND_CQ_CREATE IOCTL_ND_CQ( 0 ) 376 | #define IOCTL_ND_CQ_FREE IOCTL_ND_CQ( 1 ) 377 | #define IOCTL_ND_CQ_CANCEL_IO IOCTL_ND_CQ( 2 ) 378 | #define IOCTL_ND_CQ_GET_AFFINITY IOCTL_ND_CQ( 3 ) 379 | #define IOCTL_ND_CQ_MODIFY IOCTL_ND_CQ( 4 ) 380 | #define IOCTL_ND_CQ_NOTIFY IOCTL_ND_CQ( 5 ) 381 | #define IOCTL_ND_CQ_MAX_OPERATION 6 382 | 383 | // Memory Region IOCTLs 384 | #define IOCTL_ND_MR_CREATE IOCTL_ND_MR( 0 ) 385 | #define IOCTL_ND_MR_FREE IOCTL_ND_MR( 1 ) 386 | #define IOCTL_ND_MR_CANCEL_IO IOCTL_ND_MR( 2 ) 387 | #define IOCTL_ND_MR_REGISTER IOCTL_ND_MR( 3 ) 388 | #define IOCTL_ND_MR_DEREGISTER IOCTL_ND_MR( 4 ) 389 | #define IOCTL_NDK_MR_REGISTER IOCTL_ND_MR( 5 ) 390 | #define IOCTL_ND_MR_MAX_OPERATION 6 391 | 392 | // Memory Window IOCTLs 393 | #define IOCTL_ND_MW_CREATE IOCTL_ND_MW( 0 ) 394 | #define IOCTL_ND_MW_FREE IOCTL_ND_MW( 1 ) 395 | #define IOCTL_ND_MW_MAX_OPERATION 2 396 | 397 | // Shared Receive Queue IOCTLs 398 | #define IOCTL_ND_SRQ_CREATE IOCTL_ND_SRQ( 0 ) 399 | #define IOCTL_ND_SRQ_FREE IOCTL_ND_SRQ( 1 ) 400 | #define IOCTL_ND_SRQ_CANCEL_IO IOCTL_ND_SRQ( 2 ) 401 | #define IOCTL_ND_SRQ_GET_AFFINITY IOCTL_ND_SRQ( 3 ) 402 | #define IOCTL_ND_SRQ_MODIFY IOCTL_ND_SRQ( 4 ) 403 | #define IOCTL_ND_SRQ_NOTIFY IOCTL_ND_SRQ( 5 ) 404 | #define IOCTL_ND_SRQ_MAX_OPERATION 6 405 | 406 | // Connector IOCTLs 407 | #define IOCTL_ND_CONNECTOR_CREATE IOCTL_ND_CONNECTOR( 0 ) 408 | #define IOCTL_ND_CONNECTOR_FREE IOCTL_ND_CONNECTOR( 1 ) 409 | #define IOCTL_ND_CONNECTOR_CANCEL_IO IOCTL_ND_CONNECTOR( 2 ) 410 | #define IOCTL_ND_CONNECTOR_BIND IOCTL_ND_CONNECTOR( 3 ) 411 | #define IOCTL_ND_CONNECTOR_CONNECT IOCTL_ND_CONNECTOR( 4 ) 412 | #define IOCTL_ND_CONNECTOR_COMPLETE_CONNECT IOCTL_ND_CONNECTOR( 5 ) 413 | #define IOCTL_ND_CONNECTOR_ACCEPT IOCTL_ND_CONNECTOR( 6 ) 414 | #define IOCTL_ND_CONNECTOR_REJECT IOCTL_ND_CONNECTOR( 7 ) 415 | #define IOCTL_ND_CONNECTOR_GET_READ_LIMITS IOCTL_ND_CONNECTOR( 8 ) 416 | #define IOCTL_ND_CONNECTOR_GET_PRIVATE_DATA IOCTL_ND_CONNECTOR( 9 ) 417 | #define IOCTL_ND_CONNECTOR_GET_PEER_ADDRESS IOCTL_ND_CONNECTOR( 10 ) 418 | #define IOCTL_ND_CONNECTOR_GET_ADDRESS IOCTL_ND_CONNECTOR( 11 ) 419 | #define IOCTL_ND_CONNECTOR_NOTIFY_DISCONNECT IOCTL_ND_CONNECTOR( 12 ) 420 | #define IOCTL_ND_CONNECTOR_DISCONNECT IOCTL_ND_CONNECTOR( 13 ) 421 | #define IOCTL_ND_CONNECTOR_MAX_OPERATION 14 422 | 423 | // Listener IOCTLs 424 | #define IOCTL_ND_LISTENER_CREATE IOCTL_ND_LISTENER( 0 ) 425 | #define IOCTL_ND_LISTENER_FREE IOCTL_ND_LISTENER( 1 ) 426 | #define IOCTL_ND_LISTENER_CANCEL_IO IOCTL_ND_LISTENER( 2 ) 427 | #define IOCTL_ND_LISTENER_BIND IOCTL_ND_LISTENER( 3 ) 428 | #define IOCTL_ND_LISTENER_LISTEN IOCTL_ND_LISTENER( 4 ) 429 | #define IOCTL_ND_LISTENER_GET_ADDRESS IOCTL_ND_LISTENER( 5 ) 430 | #define IOCTL_ND_LISTENER_GET_CONNECTION_REQUEST IOCTL_ND_LISTENER( 6 ) 431 | #define IOCTL_ND_LISTENER_MAX_OPERATION 7 432 | 433 | // Queue Pair IOCTLs 434 | #define IOCTL_ND_QP_CREATE IOCTL_ND_QP( 0 ) 435 | #define IOCTL_ND_QP_CREATE_WITH_SRQ IOCTL_ND_QP( 1 ) 436 | #define IOCTL_ND_QP_FREE IOCTL_ND_QP( 2 ) 437 | #define IOCTL_ND_QP_FLUSH IOCTL_ND_QP( 3 ) 438 | #define IOCTL_ND_QP_MAX_OPERATION 4 439 | 440 | // Kernel-mode only IOCTLs (IRP_MJ_INTERNAL_DEVICE_CONTROL) 441 | #define IOCTL_NDV_PARTITION_RESOLVE_ADAPTER_ID IOCTL_ND_VIRTUAL_PARTITION( 0 ) 442 | #define IOCTL_NDV_PARTITION_CREATE IOCTL_ND_VIRTUAL_PARTITION( 1 ) 443 | #define IOCTL_NDV_PARTITION_FREE IOCTL_ND_VIRTUAL_PARTITION( 2 ) 444 | #define IOCTL_NDV_PARTITION_BIND IOCTL_ND_VIRTUAL_PARTITION( 3 ) 445 | #define IOCTL_NDV_PARTITION_UNBIND IOCTL_ND_VIRTUAL_PARTITION( 4 ) 446 | #define IOCTL_NDV_PARTITION_BIND_LUID IOCTL_ND_VIRTUAL_PARTITION( 5 ) 447 | #define IOCTL_NDV_PARTITION_MAX_OPERATION 6 448 | 449 | 450 | #if defined(_DDK_DRIVER_) || defined(_NTIFS_) 451 | 452 | __inline NTSTATUS 453 | NdValidateMemoryMapping( 454 | __in const ND_MAPPING* pMapping, 455 | ND_ACCESS_TYPE AccessType, 456 | ULONG CbLength 457 | ) 458 | { 459 | if( pMapping->MapType != NdMapMemory && pMapping->MapType != NdMapPages ) 460 | { 461 | return STATUS_INVALID_PARAMETER; 462 | } 463 | 464 | if( pMapping->MapMemory.AccessType != AccessType || 465 | pMapping->MapMemory.CbLength < CbLength ) 466 | { 467 | return STATUS_INVALID_PARAMETER; 468 | } 469 | 470 | return STATUS_SUCCESS; 471 | } 472 | 473 | __inline NTSTATUS 474 | NdValidateCoallescedMapping( 475 | __in const ND_MAPPING* pMapping, 476 | ND_ACCESS_TYPE AccessType, 477 | ULONG CbLength 478 | ) 479 | { 480 | if( pMapping->MapType != NdMapMemoryCoallesce && pMapping->MapType != NdMapPagesCoallesce ) 481 | { 482 | return STATUS_INVALID_PARAMETER; 483 | } 484 | 485 | if( pMapping->MapMemory.AccessType != AccessType || 486 | BYTE_OFFSET(pMapping->MapMemory.Address) + pMapping->MapMemory.CbLength > PAGE_SIZE || 487 | pMapping->MapMemory.CbLength != CbLength ) 488 | { 489 | return STATUS_INVALID_PARAMETER; 490 | } 491 | 492 | return STATUS_SUCCESS; 493 | } 494 | 495 | __inline NTSTATUS 496 | NdValidateIoSpaceMapping( 497 | __in const ND_MAPPING* pMapping, 498 | ND_CACHING_TYPE CacheType, 499 | ULONG CbLength 500 | ) 501 | { 502 | if( pMapping->MapType != NdMapIoSpace || 503 | pMapping->MapIoSpace.CacheType != CacheType || 504 | pMapping->MapIoSpace.CbLength != CbLength ) 505 | { 506 | return STATUS_INVALID_PARAMETER; 507 | } 508 | 509 | return STATUS_SUCCESS; 510 | } 511 | 512 | __inline void 513 | NdThunkAdapterInfo( 514 | __out ND2_ADAPTER_INFO32* pInfo32, 515 | __in const ND2_ADAPTER_INFO* pInfo 516 | ) 517 | { 518 | pInfo32->InfoVersion = pInfo->InfoVersion; 519 | pInfo32->VendorId = pInfo->VendorId; 520 | pInfo32->DeviceId = pInfo->DeviceId; 521 | pInfo32->AdapterId = pInfo->AdapterId; 522 | pInfo32->MaxRegistrationSize = (ULONG)(min(ULONG_MAX, pInfo->MaxRegistrationSize)); 523 | pInfo32->MaxWindowSize = (ULONG)(min(ULONG_MAX, pInfo->MaxWindowSize)); 524 | pInfo32->MaxInitiatorSge = pInfo->MaxInitiatorSge; 525 | pInfo32->MaxReceiveSge = pInfo->MaxReceiveSge; 526 | pInfo32->MaxReadSge = pInfo->MaxReadSge; 527 | pInfo32->MaxTransferLength = pInfo->MaxTransferLength; 528 | pInfo32->MaxInlineDataSize = pInfo->MaxInlineDataSize; 529 | pInfo32->MaxInboundReadLimit = pInfo->MaxInboundReadLimit; 530 | pInfo32->MaxOutboundReadLimit = pInfo->MaxOutboundReadLimit; 531 | pInfo32->MaxReceiveQueueDepth = pInfo->MaxReceiveQueueDepth; 532 | pInfo32->MaxInitiatorQueueDepth = pInfo->MaxInitiatorQueueDepth; 533 | pInfo32->MaxSharedReceiveQueueDepth = pInfo->MaxSharedReceiveQueueDepth; 534 | pInfo32->MaxCompletionQueueDepth = pInfo->MaxCompletionQueueDepth; 535 | pInfo32->InlineRequestThreshold = pInfo->InlineRequestThreshold; 536 | pInfo32->LargeRequestThreshold = pInfo->LargeRequestThreshold; 537 | pInfo32->MaxCallerData = pInfo->MaxCallerData; 538 | pInfo32->MaxCalleeData = pInfo->MaxCalleeData; 539 | pInfo32->AdapterFlags = pInfo->AdapterFlags; 540 | } 541 | 542 | #endif // _DDK_DRIVER_ 543 | 544 | #endif // _NDSPI_H_ 545 | -------------------------------------------------------------------------------- /src/hermes/HermesFixedRIO.hpp: -------------------------------------------------------------------------------- 1 | // HermesFixedRIO.hpp 2 | // Define an implementation of Hermes interface that uses 3 | // registered circular buffer and read/write verbs 4 | // 5 | // Each connection is split into two channels. One channel for receive 6 | // and one for send. For each channel there are two circular buffers. 7 | // The sender place data in the outgoing messages in the local "send" 8 | // buffer and try to write the remote "receive" buffer at the same 9 | // location. Read the remote "receive" buffer's trailing edge after 10 | // that. 11 | // 12 | // Trailing edge and writing edge forms natural flow control. 13 | // Bigger messages (bigger than buffer size - headers) are not supported 14 | // at this point. 15 | // 16 | 17 | #pragma once 18 | #include "stdafx.h" 19 | 20 | #include 21 | #include 22 | 23 | #include "FMem.hpp" 24 | #include "internal.hpp" 25 | #include "MiscWin.hpp" 26 | #include "Utilities.hpp" 27 | 28 | using namespace hermes; 29 | using namespace Utilities; 30 | using namespace Schedulers; 31 | 32 | namespace hinternal 33 | { 34 | 35 | // Book keeping for a circular buffers. Two for each connection 36 | // The receiving end CirTag should be registered together with 37 | // the circular buffer so the sending end can read the trailing 38 | // edge of the receiving end 39 | // 40 | struct CirTag 41 | { 42 | uint64_t TrailingEdge; 43 | uint64_t WriteEdge; 44 | }; 45 | 46 | // Initial data exchange when estabilishing connection 47 | // 48 | struct HandShake 49 | { 50 | CirTag Tag; 51 | uint64_t BufAddr; 52 | uint64_t TagAddr; 53 | 54 | uint32_t MemToken; 55 | uint32_t TagToken; 56 | }; 57 | 58 | class VerbCompletion; 59 | 60 | // Data structure for processing send/receive for a connection 61 | // Hermes create same number of Terminal and buffers pairs. 62 | // So one Terminal also currespond to one registered buffer pair 63 | // 64 | struct Terminal 65 | { 66 | static const int MAX_PENDING_READ = 2; 67 | 68 | // big blobs will be divided into multiple packets 69 | static const size_t PACKET_SIZE = 32 * SI::Ki; 70 | 71 | CirTag m_rcvEnd; 72 | CirTag m_sndEnd; 73 | 74 | // Points to the parent socket 75 | HSocketHandle m_handle; 76 | 77 | // regions can not be shared among connections, for security. 78 | IND2MemoryRegion *m_pMemRegion = nullptr; 79 | IND2MemoryRegion *m_pTagRegion = nullptr; 80 | 81 | IND2QueuePair* m_pQuePair; 82 | IND2CompletionQueue* m_pCQ; 83 | IND2Connector* m_pConnector; 84 | 85 | // Async Notifiers 86 | ConnectionNotifier* m_pConnFunc; 87 | RcvNotifier* m_pRcvFunc; 88 | 89 | // Continuation to post received message to user 90 | ContinuationBase* m_pRcvCont; 91 | ContinuationBase* m_pDisconnectCont; 92 | VerbCompletion* m_pVerbCompletion; 93 | 94 | // A locked send que, we queue up send request when the send ring 95 | // buffer is full. 96 | std::vector m_sndQue; 97 | SRWLOCK m_sndLock; 98 | std::atomic m_pendingRead = 0; 99 | 100 | uint32_t m_rmtIpAddr; 101 | uint16_t m_rmtPort; 102 | 103 | // Bigger messages are divided into multiple packets. Each 104 | // connection can not have more than one long message on each 105 | // direction at the same time. 106 | // Index value of the first packet would be 0 - num_total_packets 107 | // so if the message is 5 packet long, each of its packet index 108 | // would be: -5 1 2 3 4 109 | // So 0 is only for single packet messages. 110 | // 111 | int16_t m_mSndIdx; 112 | 113 | // total number of packets of the current receiving multi-message; 114 | int16_t m_mRcvSize; 115 | int16_t m_mRcvIdx; 116 | 117 | // buffer for collecting the content of the receiving multi-message 118 | mbuf::DisposableBuffer* m_rcvBuf; 119 | 120 | // No two threads should process the sending of a connection at 121 | // the same time. use this flag and the lock above to ensure this. 122 | bool m_sndRunning; 123 | 124 | // we are in the middle of calling client receive call back 125 | bool m_rcvProcessing; 126 | 127 | // Token used to write to remote buffer 128 | // duplicate as flag indicating the channel is still open 129 | // 130 | uint32_t m_rmtMemToken; 131 | uint32_t m_rmtTagToken; 132 | 133 | // Remote memory address for RDMA write and read operations 134 | uint64_t m_rmtBufAddr; 135 | uint64_t m_rmtTagAddr; 136 | 137 | 138 | Terminal() 139 | { 140 | VoidFlds(); 141 | } 142 | 143 | void VoidFlds() 144 | { 145 | m_rcvEnd.TrailingEdge = 0; 146 | m_rcvEnd.WriteEdge = 0; 147 | m_sndEnd.TrailingEdge = 0; 148 | m_sndEnd.WriteEdge = 0; 149 | 150 | m_handle = HSocketHandle(INVALID_HANDLE_VALUE); 151 | 152 | m_pConnector = nullptr; 153 | m_pQuePair = nullptr; 154 | m_pCQ = nullptr; 155 | 156 | m_pConnFunc = nullptr; 157 | m_pRcvFunc = nullptr; 158 | 159 | m_pRcvCont = nullptr; 160 | m_pDisconnectCont = nullptr; 161 | m_pVerbCompletion = nullptr; 162 | 163 | m_mSndIdx = 0; 164 | m_mRcvSize = 0; 165 | m_mRcvIdx = 0; 166 | m_rcvBuf = nullptr; 167 | 168 | m_sndRunning = false; 169 | m_rcvProcessing = false; 170 | 171 | m_rmtBufAddr = 0; 172 | m_rmtTagAddr = 0; 173 | m_rmtMemToken = 0; 174 | m_rmtTagToken = 0; 175 | m_rmtIpAddr = 0; 176 | m_rmtPort = 0; 177 | } 178 | 179 | // Usually called when a connection is about to start, 180 | // we save the keys the remote end handed to us 181 | // 182 | void SaveRemoteKeys(const HandShake& remote) 183 | { 184 | m_rmtBufAddr = remote.BufAddr; 185 | m_rmtTagAddr = remote.TagAddr; 186 | m_rmtMemToken = remote.MemToken; 187 | m_rmtTagToken = remote.TagToken; 188 | } 189 | 190 | // Read the edges of remote receive buffer and update 191 | // the edges of local send buffer. 192 | // 193 | void ReadRmtEdge() 194 | { 195 | auto rmtToken = m_rmtTagToken; 196 | if (rmtToken == 0) 197 | { 198 | // connection is closing, abandon ship 199 | return; 200 | } 201 | 202 | if (m_pendingRead.load() >= MAX_PENDING_READ) { 203 | return; 204 | } 205 | m_pendingRead++; 206 | 207 | ND2_SGE sge; 208 | sge.Buffer = &m_sndEnd.TrailingEdge; 209 | sge.BufferLength = sizeof(m_sndEnd.TrailingEdge); 210 | sge.MemoryRegionToken = m_pTagRegion->GetLocalToken(); 211 | 212 | auto hr = m_pQuePair->Read(this, &sge, 1, m_rmtTagAddr, rmtToken, 0); 213 | 214 | if (hr != ND_SUCCESS && hr != ND_PENDING 215 | && hr != ND_CANCELED) { 216 | Audit::OutOfLine::Fail(StatusCode(hr), L"Read remote edge failed."); 217 | } 218 | } 219 | 220 | StatusCode Prepare(uint32_t bufSize, 221 | IND2QueuePairsPool* qpPool, 222 | IND2Adapter* pAdapter, HANDLE adapterFile) 223 | { 224 | Audit::Assert(m_pQuePair == nullptr 225 | && m_pCQ == nullptr 226 | && m_pConnector == nullptr, 227 | L"ND resources leaking detected!"); 228 | 229 | m_rcvEnd.TrailingEdge = bufSize; 230 | m_rcvEnd.WriteEdge = 0; 231 | m_sndEnd.TrailingEdge = bufSize; 232 | m_sndEnd.WriteEdge = 0; 233 | 234 | return InitQues(qpPool, pAdapter, adapterFile, 235 | m_pQuePair, m_pCQ, m_pConnector); 236 | } 237 | 238 | void Cleanup() 239 | { 240 | if (m_pConnector != nullptr) { 241 | m_pConnector->Release(); 242 | m_pConnector = nullptr; 243 | 244 | m_pQuePair->Release(); 245 | m_pQuePair = nullptr; 246 | 247 | m_pCQ->Release(); 248 | m_pCQ = nullptr; 249 | } 250 | if (m_rcvBuf != nullptr) { 251 | m_rcvBuf->Dispose(); 252 | m_rcvBuf = nullptr; 253 | } 254 | VoidFlds(); 255 | } 256 | 257 | }; 258 | 259 | // Data structure for Hermes socket. The library should maintain 260 | // a table of these sockets, and gives user the handles that index 261 | // into the table. 262 | // 263 | // Pity we can not merge HSocket with Terminal, as server 264 | // sockets have no connections. Wish we can provide Java like 265 | // interface, forcing users to distinguish server socket and normal 266 | // ones. 267 | // 268 | struct HSocket 269 | { 270 | HSocket& operator=(const HSocket&) = delete; 271 | HSocket(const HSocket&) = delete; 272 | 273 | // NDv2 Listener, only used by server socket that accepting 274 | // connections 275 | IND2Listener* m_pListen = nullptr; 276 | 277 | // Index into connection pool 278 | uint32_t m_term = INVALID_TERM_ID; 279 | 280 | uint16_t m_port = 0; 281 | 282 | enum class State : uint8_t 283 | { 284 | Inpool = 0, 285 | 286 | StartToListen, 287 | Listening, 288 | 289 | // On server, a connection request received 290 | Accept1, 291 | 292 | // a client trying to connect 293 | Connecting, 294 | 295 | // Both server and client, both accepted 296 | ConnAgreed, 297 | 298 | // a client received conntion ack from server, 299 | // i.e. Connect() completed 300 | ConnAck, 301 | 302 | Connected, 303 | 304 | Stopping, 305 | Disconnected 306 | }; 307 | 308 | State m_state = State::Inpool; 309 | 310 | // Socket handle is just a index to socket object table. we use the 311 | // extra bits here to defend against dangling handle 312 | HSocketHandle m_handle; 313 | }; 314 | 315 | enum class MsgType : uint16_t 316 | { 317 | Single, 318 | Multi // one segment that belongs to a sequence of messages 319 | }; 320 | 321 | // Header and footer of the message 322 | struct MsgEnd 323 | { 324 | uint64_t Crc; 325 | uint32_t Size; 326 | int16_t Seq; // sequence number for multi messages. 327 | MsgType Type; 328 | }; 329 | static_assert(sizeof(MsgEnd) == MSG_ALIGN, "Header & footer should align"); 330 | 331 | class HermesFixedRIO; 332 | 333 | // Thread in a tight loop to poll all terminals for incoming data 334 | // 335 | class Poller : public Work 336 | { 337 | HermesFixedRIO& m_root; 338 | uint32_t m_idx = 1ul; 339 | public: 340 | Poller(HermesFixedRIO& root) 341 | : m_root(root) 342 | {} 343 | 344 | void Run( 345 | _In_ WorkerThread& thread, 346 | intptr_t continuationHandle, 347 | uint32_t length 348 | ) override; 349 | }; 350 | 351 | 352 | // Implementation of Hermes interface, root of the library. Using fixed 353 | // ring buffers for connection. 354 | // 355 | // Currently the max number of connections is also fixed. 356 | // We plan to group connection data structure into pages and develop 357 | // dynamic management of these pages to remove this restriction later. 358 | // 359 | class HermesFixedRIO : public Hermes, public Work 360 | { 361 | friend class Poller; 362 | friend class Conveyor; 363 | friend class TerminalCloser; 364 | friend class VerbCompletion; 365 | 366 | HermesFixedRIO() = delete; 367 | HermesFixedRIO(const HermesFixedRIO&) = delete; 368 | HermesFixedRIO& operator=(const HermesFixedRIO&) = delete; 369 | 370 | // ND Adapter related 371 | // 372 | IND2Adapter *m_pAdapter; 373 | IND2QueuePairsPool *m_QueuePairsPool; 374 | 375 | // IOCP related 376 | // 377 | HANDLE m_hAdapterFile; 378 | HANDLE m_hIocp; 379 | std::unique_ptr m_pScheduler; 380 | 381 | Poller m_poller; 382 | 383 | // Buffers, connections and sockets 384 | std::unique_ptr m_pMemory; 385 | gsl::span m_buffers; 386 | gsl::span m_connections; 387 | gsl::span m_sockTbl; 388 | 389 | // Pools for connections and sockets, number is used to index into 390 | // connection object array. 391 | // Note the index we give user start with 1, leaving 0 as 392 | // invalid to comform to nullptr value. 393 | // 394 | mbuf::CircularQue m_connPool; 395 | mbuf::CircularQue m_sockPool; 396 | 397 | HOverlapPool m_overlapPool; 398 | 399 | std::unique_ptr m_pBuffers; 400 | 401 | const uint32_t m_bufSize; 402 | const uint32_t m_maxConnection; 403 | uint32_t m_homeIp; 404 | 405 | bool m_closing = false; 406 | 407 | // Allocate a socket structure 408 | // return index to the socket table 409 | // 410 | HSocket* AllocateSocket(StatusCode& err) 411 | { 412 | uint32_t id = INVALID_SOCK_ID; 413 | auto success = m_sockPool.Get(id); 414 | if (!success) { 415 | err = StatusCode(E_NOT_SUFFICIENT_BUFFER); 416 | return nullptr; 417 | } 418 | 419 | auto& sock = *GetSocket(id); 420 | Audit::Assert(sock.m_state == HSocket::State::Inpool, 421 | L"Socket state changed while in socket pool!"); 422 | Audit::Assert(sock.m_term == INVALID_TERM_ID 423 | && sock.m_pListen == nullptr, 424 | L"Socket state not cleared."); 425 | Audit::Assert(HandleToId(sock.m_handle) == id, 426 | L"Lower 32b of handle should be the index"); 427 | 428 | sock.m_state = HSocket::State::Disconnected; 429 | err = H_ok; 430 | return &sock; 431 | } 432 | 433 | void FreeSocket(uint32_t id) 434 | { 435 | auto& sock = *GetSocket(id); 436 | Audit::Assert(sock.m_state != HSocket::State::Inpool, 437 | L"Double free of socket"); 438 | sock.m_state = HSocket::State::Inpool; 439 | sock.m_handle += 1ull << 32; // defend against dangling handles 440 | Audit::Assert(HandleToId(sock.m_handle) == id, 441 | L"Lower 32b of handle should be the index"); 442 | 443 | Audit::Assert(m_sockPool.Add(id), 444 | L"Unexpected sock pool overflow during deallocation"); 445 | } 446 | 447 | uint32_t HandleToId(HSocketHandle handle) 448 | { 449 | return uint32_t(handle); 450 | } 451 | 452 | HSocket* GetSocket(uint32_t id) 453 | { 454 | // user id start from 0, but vector index starts from 0 455 | if (id >= 1 && id <= m_sockPool.GetCapacity()) 456 | return &m_sockTbl[id - 1]; 457 | else return nullptr; 458 | } 459 | 460 | // Allocate a handle to all data structure needed for a connected 461 | // socket, including buffer pair, queue pair, completion queue 462 | // connector. 463 | // 464 | // When failed, returns INVALID_TERM_ID with error code set 465 | // to err parameter 466 | // 467 | uint32_t AllocTerminal(StatusCode& err, HSocketHandle parent) 468 | { 469 | uint32_t id; 470 | Audit::Assert(m_connPool.Get(id), 471 | L"Exhausted connection!"); 472 | 473 | auto ptr = GetTerminal(id); 474 | Audit::Assert(ptr->m_rcvEnd.TrailingEdge == 0 475 | && ptr->m_sndEnd.TrailingEdge == 0, 476 | L"Invalid connection state from connection pool"); 477 | 478 | err = ptr->Prepare(m_bufSize, 479 | m_QueuePairsPool, m_pAdapter, m_hAdapterFile); 480 | if (err != H_ok) 481 | { 482 | ptr->m_sndEnd.TrailingEdge = m_bufSize; 483 | FreeTerminal(id); 484 | return INVALID_TERM_ID; 485 | } 486 | CreateMemRegions(id); 487 | ptr->m_handle = parent; 488 | return id; 489 | } 490 | 491 | // Deallocate connection information and buffers, release all ND 492 | // related resources 493 | // 494 | void FreeTerminal(uint32_t id) 495 | { 496 | auto ptr = GetTerminal(id); 497 | Audit::Assert(ptr->m_rcvEnd.TrailingEdge != 0 498 | && ptr->m_sndEnd.TrailingEdge != 0, 499 | L"Double free to connection pool"); 500 | 501 | ptr->Cleanup(); 502 | Audit::Assert(m_connPool.Add(id), 503 | L"Connection pool internal error."); 504 | } 505 | 506 | Terminal* GetTerminal(uint32_t conId) 507 | { 508 | conId--; // user index start with 1 509 | Audit::Assert(conId < m_maxConnection, 510 | L"Invalid Connection Id"); 511 | return &(m_connections[conId]); 512 | } 513 | 514 | // Start the terminal as the passengers are coming 515 | // 516 | void StartTerminal(uint32_t termId, const HandShake& handShake); 517 | 518 | gsl::span GetBufPair(uint32_t conId) 519 | { 520 | conId--; // user index start with 1 521 | Audit::Assert(conId < m_maxConnection, 522 | L"Invalid Connection Id"); 523 | 524 | // two buffers per connection 525 | auto offset = conId * m_bufSize * 2; 526 | 527 | return m_buffers.subspan(offset, m_bufSize * 2); 528 | } 529 | 530 | gsl::span GetRcvBuf(uint32_t conId) 531 | { 532 | conId--; // user index start with 1 533 | Audit::Assert(conId < m_maxConnection, 534 | L"Invalid Connection Id"); 535 | 536 | // two buffers per connection 537 | auto offset = conId * m_bufSize * 2; 538 | 539 | return m_buffers.subspan(offset, m_bufSize); 540 | } 541 | 542 | gsl::span GetSndBuf(uint32_t conId) 543 | { 544 | conId--; // user index start with 1 545 | Audit::Assert(conId < m_maxConnection, 546 | L"Invalid Connection Id"); 547 | 548 | // two buffers per connection and we want the later one 549 | auto offset = conId * m_bufSize * 2 + m_bufSize; 550 | 551 | return m_buffers.subspan(offset, m_bufSize); 552 | } 553 | 554 | void PrepareHandShakeData(uint32_t termId, _Out_ HandShake& res) 555 | { 556 | auto pTerm = GetTerminal(termId); 557 | res.Tag.WriteEdge = pTerm->m_rcvEnd.WriteEdge; 558 | res.Tag.TrailingEdge = pTerm->m_rcvEnd.TrailingEdge; 559 | res.TagAddr = uint64_t(&pTerm->m_rcvEnd.TrailingEdge); 560 | res.BufAddr = uint64_t(GetRcvBuf(termId).data()); 561 | 562 | while (pTerm->m_pMemRegion == nullptr || pTerm->m_pTagRegion == nullptr) 563 | { 564 | // really crappy busy waiting!!! Hopefully it happens rarely 565 | // as we leave enough room between this and register of memory 566 | // regions. 567 | std::this_thread::yield(); 568 | } 569 | res.MemToken = pTerm->m_pMemRegion->GetRemoteToken(); 570 | res.TagToken = pTerm->m_pTagRegion->GetRemoteToken(); 571 | } 572 | 573 | // Called before setting up connection to create memory regions. 574 | // 575 | // Memory regions control tokens, which gives remote server access 576 | // to our memory. We don't want tokens to be shared by any two 577 | // remote servers. So we must destroy and recreate them every time 578 | // 579 | void CreateMemRegions(uint32_t conId); 580 | 581 | // Try to close a socket if it is in a stead state: 582 | // connected, listening or disconnected. 583 | // return whether successfully closed 584 | // 585 | bool TryCloseSocket(HSocket * pSock, StatusCode err); 586 | 587 | // 588 | // Initialization sub contractors, must be called from constructor 589 | // putting into seperate functions just for readability 590 | // 591 | 592 | // Slice large page buffers into array of buffer pairs Terminal 593 | // 594 | void SliceNregister(); 595 | 596 | public: 597 | // Constructor, must be called from the factory; 598 | HermesFixedRIO( 599 | size_t maxConcurrentConnections, 600 | size_t bufferSize, 601 | std::unique_ptr& pPage 602 | ); 603 | 604 | uint32_t GetHomeIp() override { return m_homeIp; } 605 | 606 | HSocketHandle CreateSocket( 607 | _Out_ StatusCode& error 608 | ) override 609 | { 610 | if (m_closing) { 611 | error = StatusCode(ND_CANCELED); 612 | return intptr_t(INVALID_HANDLE_VALUE); 613 | } 614 | 615 | auto pSock = AllocateSocket(error); 616 | if (pSock == nullptr) { 617 | return intptr_t(INVALID_HANDLE_VALUE); 618 | } 619 | // no hurry to allocate connection or setup receive 620 | // thred yet, wait until accept or connect 621 | 622 | return pSock->m_handle; 623 | } 624 | 625 | ~HermesFixedRIO() 626 | { 627 | m_closing = true; 628 | auto workToDo = true; 629 | while (workToDo) 630 | { 631 | workToDo = false; 632 | for (auto id = uint32_t(1); id <= m_sockPool.GetCapacity(); id++) 633 | { 634 | auto& sock = m_sockTbl[id - 1]; 635 | if (sock.m_state == HSocket::State::Inpool) 636 | continue; 637 | 638 | workToDo = true; 639 | wchar_t msg[256]; 640 | swprintf_s(msg, L"Closing socket %u, in state %u", 641 | id, sock.m_state); 642 | Tracer::LogWarning(H_unexpected, msg); 643 | TryCloseSocket(&sock, StatusCode(ND_CANCELED)); 644 | } 645 | } 646 | 647 | m_pAdapter->Release(); 648 | if (m_QueuePairsPool != nullptr) 649 | { 650 | m_QueuePairsPool->Release(); 651 | } 652 | 653 | Tracer::DisposeLogging(); 654 | } 655 | 656 | // Begin Listen on a certain port. automatically assigned if 0 657 | // 658 | StatusCode Listen(HSocketHandle handle, uint16_t port) override; 659 | 660 | // Signal that one connection can be accepted. new socket 661 | // of that connection is provided async by connectionCallback 662 | // 663 | StatusCode Accept( 664 | HSocketHandle handle, 665 | 666 | // hook for Async return of the connected socket 667 | _In_ ConnectionNotifier& connectCallback, 668 | 669 | // A receive call back, will be assigned to the connected 670 | // socket, and triggered whenever a new message received 671 | // on that connected socket. 672 | // 673 | _In_ RcvNotifier& rcvCallback 674 | ) override; 675 | 676 | // Called when we have a connection request arrived, i.e. 677 | // completion of Listen->GetConnectionRequest(connector); 678 | // 679 | void ProcessConnReq(HSocket& connSock, HRESULT hr, ActionArena* pArena); 680 | 681 | // Called when async call connector->Accept is finished 682 | // 683 | void OnConnAccepted(HSocket& connsock, HRESULT hr, ActionArena* pArena); 684 | 685 | // Async call to connecting to a remote end point ==> WSA connect 686 | // new socket of the newly established connection is provided async 687 | // by connectionCallback 688 | StatusCode Connect( 689 | HSocketHandle sock, 690 | 691 | uint32_t remoteIp, 692 | uint16_t remotePort, 693 | 694 | // hook for async notification of connection success or failure 695 | // socket parameter should be this socket. 696 | _In_ ConnectionNotifier& connectCallback, 697 | 698 | // A receive call back, once connected, new messages received 699 | // will trigger this 700 | // 701 | _In_ RcvNotifier& rcvCallback 702 | ) override; 703 | 704 | // Called on completion of async Connect call. 705 | // server accepted, need to complete connect 706 | // 707 | void OnConnAck( 708 | // socket on which we need to call complete connect 709 | HSocket& sock, 710 | 711 | // return code of the Connect funciton 712 | HRESULT hr, 713 | 714 | // memory on which the async 715 | ActionArena* pArena); 716 | 717 | 718 | // Async send, notification of completion will be carried by 719 | // sendCallback provided to Connect or Accept method 720 | // 721 | StatusCode Send( 722 | HSocketHandle sock, 723 | 724 | // place holder for the client to identify this operation 725 | // will be pass back to client in sendCallback 726 | _In_ void* sndContext, 727 | 728 | // Buffer must be available for the duration of the async 729 | // operation, until notified by sendCallback 730 | _In_ const gsl::span buf, 731 | 732 | // A send status call back, async notification of send completion 733 | _In_ SendCompletionNotifier& sendCallback 734 | ) override; 735 | 736 | // Put send request to circular buffer and write to remote, 737 | // read remote trailing edge, 738 | // Expect caller to ensure this function does not overlap 739 | // with itself. 740 | // 741 | void ProcessSendQ(uint32_t termId); 742 | 743 | void CloseSocket(HSocketHandle handle, StatusCode err) override; 744 | 745 | // Triggered by IOCP notification on the adapter file handle 746 | // Simply redirect to AsyncJob registered on the HOverlap obj 747 | // and then release the HOverlap obj 748 | // 749 | void Run( 750 | _In_ WorkerThread& /*thread*/, 751 | intptr_t continuationHandle, 752 | uint32_t /*length*/ 753 | ) override 754 | { 755 | auto pOv = reinterpret_cast(continuationHandle); 756 | auto pContext = HOverlap::GetContext(pOv); 757 | auto hr = pContext->PReceiver->GetOverlappedResult(pOv, false); 758 | Audit::Assert(hr != ND_PENDING, 759 | L"Pending status not expected after IOCP notification!"); 760 | 761 | (*(pContext->PNext))(hr, m_pScheduler->GetArena(pContext->PNext)); 762 | 763 | m_overlapPool.FreeObj(pContext); 764 | } 765 | 766 | Scheduler* GetScheduler() 767 | { 768 | return m_pScheduler.get(); 769 | } 770 | 771 | // Only valid for socket in connected or listening state 772 | // returns 0 when unknown. 773 | uint16_t GetHomePort(HSocketHandle handle) override 774 | { 775 | auto pSock = GetSocket(HandleToId(handle)); 776 | if (pSock->m_handle != handle) { 777 | return 0; 778 | } 779 | 780 | return pSock->m_port; 781 | } 782 | 783 | // Only valid for connected sockets, return 0 when unknown. 784 | uint32_t GetRemoteIp(HSocketHandle handle) override 785 | { 786 | auto pSock = GetSocket(HandleToId(handle)); 787 | if (pSock == nullptr || pSock->m_handle != handle 788 | || pSock->m_term == INVALID_TERM_ID) { 789 | return 0; 790 | } 791 | 792 | return GetTerminal(pSock->m_term)->m_rmtIpAddr; 793 | } 794 | 795 | uint16_t GetRemotePort(HSocketHandle handle) override 796 | { 797 | auto pSock = GetSocket(HandleToId(handle)); 798 | if (pSock->m_handle != handle 799 | || pSock->m_term == INVALID_TERM_ID) { 800 | return 0; 801 | } 802 | 803 | return GetTerminal(pSock->m_term)->m_rmtPort; 804 | } 805 | 806 | }; 807 | 808 | // Belongs to a certain terminal. 809 | // A continuation to close the connection and release the socket 810 | // 811 | class TerminalCloser : public ContinuationBase 812 | { 813 | HermesFixedRIO& m_root; 814 | uint32_t m_termId; 815 | public: 816 | TerminalCloser( 817 | // Thread for sequentializing all receive related actions 818 | Activity& act, 819 | 820 | HermesFixedRIO& root, 821 | 822 | // Terminal for the connection 823 | uint32_t termId 824 | ) 825 | : ContinuationBase(act) 826 | , m_termId(termId) 827 | , m_root(root) 828 | {} 829 | 830 | void Cleanup() 831 | { 832 | // have not found anything needs cleanup yet. 833 | } 834 | 835 | void OnReady( 836 | _In_ WorkerThread& thread, 837 | intptr_t continuationHandle, 838 | uint32_t length 839 | ) override; 840 | 841 | }; 842 | 843 | 844 | // Belongs to a terminal. 845 | // Triggered when the poller discovered we have incoming message. 846 | // So we call user call back. If the user has a call back that runs 847 | // too long, then it would harm the speed of this single connection 848 | // not others. 849 | // 850 | class Conveyor : public ContinuationBase 851 | { 852 | HermesFixedRIO& m_root; 853 | uint32_t m_termId; 854 | public: 855 | Conveyor( 856 | // Thread for sequentializing all receive related actions 857 | Activity& act, 858 | 859 | HermesFixedRIO& root, 860 | 861 | // Terminal for the connection 862 | uint32_t termId 863 | ) 864 | : ContinuationBase(act) 865 | , m_termId(termId) 866 | , m_root(root) 867 | {} 868 | 869 | void Cleanup() 870 | { 871 | // have not found anything needs cleanup yet. 872 | } 873 | 874 | void OnReady( 875 | _In_ WorkerThread& thread, 876 | intptr_t continuationHandle, 877 | uint32_t length 878 | ) override; 879 | }; 880 | 881 | 882 | // Completion handler for ND completion queue. 883 | // maybe we can have all connections use one completion queue. 884 | // 885 | class VerbCompletion : public AsyncJob 886 | { 887 | HermesFixedRIO& m_root; 888 | 889 | uint64_t m_oldTrailing; 890 | uint32_t m_termId; 891 | 892 | bool m_shutdown = false; 893 | 894 | public: 895 | VerbCompletion(HermesFixedRIO& root, 896 | uint32_t termId) 897 | : m_root(root) 898 | , m_termId(termId) 899 | { 900 | m_oldTrailing = m_root.GetTerminal(m_termId)->m_rcvEnd.TrailingEdge; 901 | } 902 | 903 | void RequestShutdown() { m_shutdown = true; } 904 | 905 | virtual void operator()( 906 | // Result code from GetOverlappedResult(); 907 | HRESULT /*hr*/, 908 | 909 | // Arena on which this object is allocated. 910 | _In_ Schedulers::ActionArena* pArena) override; 911 | }; 912 | 913 | // A frame for data layout on ring buffer 914 | // 915 | struct DFrame { 916 | // header 917 | MsgEnd* m_pStart; 918 | 919 | // actual data, maybe split by ring buf end 920 | gsl::span m_views[2]; 921 | 922 | // footer 923 | MsgEnd* m_pEnd; 924 | }; 925 | 926 | 927 | // Given a starting edge and size, locate the header, footer, and data 928 | // segments 929 | // 930 | inline void LocateInRingBuf( 931 | // ring buffer 932 | _In_ gsl::span buffer, 933 | 934 | // start edge and size of blob plus header footer 935 | uint64_t startEdge, size_t size, 936 | 937 | _Out_ DFrame& rec) 938 | { 939 | auto bufSize = buffer.size_bytes(); 940 | Audit::Assert(bufSize > 0 && mbuf::IsPower2(bufSize), 941 | L"Size of ring buffer must be power of 2"); 942 | 943 | auto offset = startEdge & (bufSize - 1); // mod for power of 2 value 944 | Audit::Assert(offset <= (bufSize - sizeof(MsgEnd)), 945 | L"MsgEnd splited into two"); 946 | 947 | rec.m_pStart = reinterpret_cast(&buffer[offset]); 948 | auto blobSize = size - 2 * sizeof(MsgEnd); 949 | offset += sizeof(MsgEnd); 950 | 951 | auto len1 = std::min(blobSize, bufSize - offset); 952 | auto len2 = blobSize - len1; 953 | 954 | rec.m_views[0] = buffer.subspan(offset, len1); 955 | rec.m_views[1] = buffer.subspan(0, len2); 956 | 957 | auto endPos = (len2 > 0) ? len2 : 958 | (offset + len1) & (bufSize - 1); 959 | rec.m_pEnd = reinterpret_cast(&buffer[endPos]); 960 | } 961 | 962 | } 963 | -------------------------------------------------------------------------------- /src/ndv2lib/ndspi.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Module Name: 6 | 7 | ndspi.h 8 | 9 | Abstract: 10 | 11 | NetworkDirect Service Provider Interfaces 12 | 13 | Environment: 14 | 15 | User mode 16 | 17 | --*/ 18 | 19 | #pragma once 20 | 21 | #ifndef _NDSPI_H_ 22 | #define _NDSPI_H_ 23 | 24 | #include 25 | #include 26 | #include "ndstatus.h" 27 | #include "nddef.h" 28 | 29 | 30 | // 31 | // Overlapped object 32 | // 33 | #undef INTERFACE 34 | #define INTERFACE IND2Overlapped 35 | 36 | // {ABF72719-B016-4a40-A6F7-622791A7044C} 37 | DEFINE_GUID(IID_IND2Overlapped, 38 | 0xabf72719, 0xb016, 0x4a40, 0xa6, 0xf7, 0x62, 0x27, 0x91, 0xa7, 0x4, 0x4c); 39 | 40 | DECLARE_INTERFACE_(IND2Overlapped, IUnknown) 41 | { 42 | // *** IUnknown methods *** 43 | IFACEMETHOD(QueryInterface)( 44 | THIS_ 45 | REFIID riid, 46 | __deref_out LPVOID* ppvObj 47 | ) PURE; 48 | 49 | IFACEMETHOD_(ULONG,AddRef)( 50 | THIS 51 | ) PURE; 52 | 53 | IFACEMETHOD_(ULONG,Release)( 54 | THIS 55 | ) PURE; 56 | 57 | // *** IND2Overlapped methods *** 58 | STDMETHOD(CancelOverlappedRequests)( 59 | THIS 60 | ) PURE; 61 | 62 | STDMETHOD(GetOverlappedResult)( 63 | THIS_ 64 | __in OVERLAPPED* pOverlapped, 65 | bool wait 66 | ) PURE; 67 | }; 68 | 69 | 70 | // 71 | // Completion Queue 72 | // 73 | #undef INTERFACE 74 | #define INTERFACE IND2CompletionQueue 75 | 76 | // {20CC445E-64A0-4cbb-AA75-F6A7251FDA9E} 77 | DEFINE_GUID(IID_IND2CompletionQueue, 78 | 0x20cc445e, 0x64a0, 0x4cbb, 0xaa, 0x75, 0xf6, 0xa7, 0x25, 0x1f, 0xda, 0x9e); 79 | 80 | DECLARE_INTERFACE_(IND2CompletionQueue, IND2Overlapped) 81 | { 82 | // *** IUnknown methods *** 83 | IFACEMETHOD(QueryInterface)( 84 | THIS_ 85 | REFIID riid, 86 | __deref_out LPVOID* ppvObj 87 | ) PURE; 88 | 89 | IFACEMETHOD_(ULONG,AddRef)( 90 | THIS 91 | ) PURE; 92 | 93 | IFACEMETHOD_(ULONG,Release)( 94 | THIS 95 | ) PURE; 96 | 97 | // *** IND2Overlapped methods *** 98 | IFACEMETHOD(CancelOverlappedRequests)( 99 | THIS 100 | ) PURE; 101 | 102 | IFACEMETHOD(GetOverlappedResult)( 103 | THIS_ 104 | __in OVERLAPPED* pOverlapped, 105 | bool wait 106 | ) PURE; 107 | 108 | // *** IND2CompletionQueue methods *** 109 | STDMETHOD(GetNotifyAffinity)( 110 | THIS_ 111 | __out USHORT* pGroup, 112 | __out KAFFINITY* pAffinity 113 | ) PURE; 114 | 115 | STDMETHOD(Resize)( 116 | THIS_ 117 | ULONG queueDepth 118 | ) PURE; 119 | 120 | STDMETHOD(Notify)( 121 | THIS_ 122 | ULONG type, 123 | __inout OVERLAPPED* pOverlapped 124 | ) PURE; 125 | 126 | STDMETHOD_(ULONG,GetResults)( 127 | THIS_ 128 | __out_ecount_part(nResults,return) ND2_RESULT results[], 129 | ULONG nResults 130 | ) PURE; 131 | }; 132 | 133 | 134 | // 135 | // Shared Receive Queue 136 | // 137 | #undef INTERFACE 138 | #define INTERFACE IND2SharedReceiveQueue 139 | 140 | // {AABD67DC-459A-4db1-826B-56CFCC278883} 141 | DEFINE_GUID(IID_IND2SharedReceiveQueue, 142 | 0xaabd67dc, 0x459a, 0x4db1, 0x82, 0x6b, 0x56, 0xcf, 0xcc, 0x27, 0x88, 0x83); 143 | 144 | DECLARE_INTERFACE_(IND2SharedReceiveQueue, IND2Overlapped) 145 | { 146 | // *** IUnknown methods *** 147 | IFACEMETHOD(QueryInterface)( 148 | THIS_ 149 | REFIID riid, 150 | __deref_out LPVOID* ppvObj 151 | ) PURE; 152 | 153 | IFACEMETHOD_(ULONG,AddRef)( 154 | THIS 155 | ) PURE; 156 | 157 | IFACEMETHOD_(ULONG,Release)( 158 | THIS 159 | ) PURE; 160 | 161 | // *** IND2Overlapped methods *** 162 | IFACEMETHOD(CancelOverlappedRequests)( 163 | THIS 164 | ) PURE; 165 | 166 | IFACEMETHOD(GetOverlappedResult)( 167 | THIS_ 168 | __in OVERLAPPED* pOverlapped, 169 | bool wait 170 | ) PURE; 171 | 172 | // *** IND2SharedReceiveQueue methods *** 173 | STDMETHOD(GetNotifyAffinity)( 174 | THIS_ 175 | __out USHORT* pGroup, 176 | __out KAFFINITY* pAffinity 177 | ) PURE; 178 | 179 | STDMETHOD(Modify)( 180 | THIS_ 181 | ULONG queueDepth, 182 | ULONG notifyThreshold 183 | ) PURE; 184 | 185 | STDMETHOD(Notify)( 186 | THIS_ 187 | __inout OVERLAPPED* pOverlapped 188 | ) PURE; 189 | 190 | STDMETHOD(Receive)( 191 | THIS_ 192 | __in VOID* requestContext, 193 | __in_ecount_opt(nSge) const ND2_SGE sge[], 194 | ULONG nSge 195 | ) PURE; 196 | }; 197 | 198 | 199 | // 200 | // Memory Window 201 | // 202 | #undef INTERFACE 203 | #define INTERFACE IND2MemoryWindow 204 | 205 | // {070FE1F5-0AB5-4361-88DB-974BA704D4B9} 206 | DEFINE_GUID(IID_IND2MemoryWindow, 207 | 0x70fe1f5, 0xab5, 0x4361, 0x88, 0xdb, 0x97, 0x4b, 0xa7, 0x4, 0xd4, 0xb9); 208 | 209 | DECLARE_INTERFACE_(IND2MemoryWindow, IUnknown) 210 | { 211 | // *** IUnknown methods *** 212 | IFACEMETHOD(QueryInterface)( 213 | THIS_ 214 | REFIID riid, 215 | __deref_out LPVOID* ppvObj 216 | ) PURE; 217 | 218 | IFACEMETHOD_(ULONG,AddRef)( 219 | THIS 220 | ) PURE; 221 | 222 | IFACEMETHOD_(ULONG,Release)( 223 | THIS 224 | ) PURE; 225 | 226 | // *** IND2MemoryWindow methods *** 227 | STDMETHOD_(UINT32, GetRemoteToken)( 228 | THIS 229 | ) PURE; 230 | }; 231 | 232 | 233 | // 234 | // Memory Region 235 | // 236 | #undef INTERFACE 237 | #define INTERFACE IND2MemoryRegion 238 | 239 | // {55DFEA2F-BC56-4982-8A45-0301BE46C413} 240 | DEFINE_GUID(IID_IND2MemoryRegion, 241 | 0x55dfea2f, 0xbc56, 0x4982, 0x8a, 0x45, 0x3, 0x1, 0xbe, 0x46, 0xc4, 0x13); 242 | 243 | DECLARE_INTERFACE_(IND2MemoryRegion, IND2Overlapped) 244 | { 245 | // *** IUnknown methods *** 246 | IFACEMETHOD(QueryInterface)( 247 | THIS_ 248 | REFIID riid, 249 | __deref_out LPVOID* ppvObj 250 | ) PURE; 251 | 252 | IFACEMETHOD_(ULONG,AddRef)( 253 | THIS 254 | ) PURE; 255 | 256 | IFACEMETHOD_(ULONG,Release)( 257 | THIS 258 | ) PURE; 259 | 260 | // *** IND2Overlapped methods *** 261 | IFACEMETHOD(CancelOverlappedRequests)( 262 | THIS 263 | ) PURE; 264 | 265 | IFACEMETHOD(GetOverlappedResult)( 266 | THIS_ 267 | __in OVERLAPPED* pOverlapped, 268 | bool wait 269 | ) PURE; 270 | 271 | // *** IND2MemoryRegion methods *** 272 | 273 | ////////////////////////////////// 274 | // flags - Combination of ND_MR_FLAG_ALLOW_XXX. Note remote flags imply local. 275 | STDMETHOD(Register)( 276 | THIS_ 277 | __in_bcount(cbBuffer) const VOID* pBuffer, 278 | SIZE_T cbBuffer, 279 | ULONG flags, 280 | __inout OVERLAPPED* pOverlapped 281 | ) PURE; 282 | 283 | STDMETHOD(Deregister)( 284 | THIS_ 285 | __inout OVERLAPPED* pOverlapped 286 | ) PURE; 287 | 288 | STDMETHOD_(UINT32, GetLocalToken)( 289 | THIS 290 | ) PURE; 291 | 292 | STDMETHOD_(UINT32, GetRemoteToken)( 293 | THIS 294 | ) PURE; 295 | }; 296 | 297 | 298 | // 299 | // QueuePair 300 | // 301 | #undef INTERFACE 302 | #define INTERFACE IND2QueuePair 303 | 304 | // {EEF2F332-B75D-4063-BCE3-3A0BAD2D02CE} 305 | DEFINE_GUID(IID_IND2QueuePair, 306 | 0xeef2f332, 0xb75d, 0x4063, 0xbc, 0xe3, 0x3a, 0xb, 0xad, 0x2d, 0x2, 0xce); 307 | 308 | DECLARE_INTERFACE_(IND2QueuePair, IUnknown) 309 | { 310 | // *** IUnknown methods *** 311 | IFACEMETHOD(QueryInterface)( 312 | THIS_ 313 | REFIID riid, 314 | __deref_out LPVOID* ppvObj 315 | ) PURE; 316 | 317 | IFACEMETHOD_(ULONG,AddRef)( 318 | THIS 319 | ) PURE; 320 | 321 | IFACEMETHOD_(ULONG,Release)( 322 | THIS 323 | ) PURE; 324 | 325 | // *** IND2QueuePair methods *** 326 | STDMETHOD(Flush)( 327 | THIS 328 | ) PURE; 329 | 330 | STDMETHOD(Send)( 331 | THIS_ 332 | __in_opt VOID* requestContext, 333 | __in_ecount_opt(nSge) const ND2_SGE sge[], 334 | ULONG nSge, 335 | ULONG flags 336 | ) PURE; 337 | 338 | STDMETHOD(Receive)( 339 | THIS_ 340 | __in_opt VOID* requestContext, 341 | __in_ecount_opt(nSge) const ND2_SGE sge[], 342 | ULONG nSge 343 | ) PURE; 344 | 345 | // RemoteToken available thorugh IND2Mw::GetRemoteToken. 346 | STDMETHOD(Bind)( 347 | THIS_ 348 | __in_opt VOID* requestContext, 349 | __in IUnknown* pMemoryRegion, 350 | __inout IUnknown* pMemoryWindow, 351 | __in_bcount(cbBuffer) const VOID* pBuffer, 352 | SIZE_T cbBuffer, 353 | ULONG flags 354 | ) PURE; 355 | 356 | STDMETHOD(Invalidate)( 357 | THIS_ 358 | __in_opt VOID* requestContext, 359 | __in IUnknown* pMemoryWindow, 360 | ULONG flags 361 | ) PURE; 362 | 363 | STDMETHOD(Read)( 364 | THIS_ 365 | __in_opt VOID* requestContext, 366 | __in_ecount_opt(nSge) const ND2_SGE sge[], 367 | ULONG nSge, 368 | UINT64 remoteAddress, 369 | UINT32 remoteToken, 370 | ULONG flags 371 | ) PURE; 372 | 373 | STDMETHOD(Write)( 374 | THIS_ 375 | __in_opt VOID* requestContext, 376 | __in_ecount_opt(nSge) const ND2_SGE sge[], 377 | ULONG nSge, 378 | UINT64 remoteAddress, 379 | UINT32 remoteToken, 380 | ULONG flags 381 | ) PURE; 382 | }; 383 | 384 | 385 | // 386 | // Connector 387 | // 388 | #undef INTERFACE 389 | #define INTERFACE IND2Connector 390 | 391 | // {7DD615C4-6B4C-4866-950C-F3B1D25A5302} 392 | DEFINE_GUID(IID_IND2Connector, 393 | 0x7dd615c4, 0x6b4c, 0x4866, 0x95, 0xc, 0xf3, 0xb1, 0xd2, 0x5a, 0x53, 0x2); 394 | 395 | DECLARE_INTERFACE_(IND2Connector, IND2Overlapped) 396 | { 397 | // *** IUnknown methods *** 398 | IFACEMETHOD(QueryInterface)( 399 | THIS_ 400 | REFIID riid, 401 | __deref_out LPVOID* ppvObj 402 | ) PURE; 403 | 404 | IFACEMETHOD_(ULONG,AddRef)( 405 | THIS 406 | ) PURE; 407 | 408 | IFACEMETHOD_(ULONG,Release)( 409 | THIS 410 | ) PURE; 411 | 412 | // *** IND2Overlapped methods *** 413 | IFACEMETHOD(CancelOverlappedRequests)( 414 | THIS 415 | ) PURE; 416 | 417 | IFACEMETHOD(GetOverlappedResult)( 418 | THIS_ 419 | __in OVERLAPPED* pOverlapped, 420 | bool wait 421 | ) PURE; 422 | 423 | // *** IND2Connector methods *** 424 | STDMETHOD(Bind)( 425 | THIS_ 426 | __in_bcount(cbAddress) const struct sockaddr* pAddress, 427 | ULONG cbAddress 428 | ) PURE; 429 | 430 | STDMETHOD(Connect)( 431 | THIS_ 432 | __in IUnknown* pQueuePair, 433 | __in_bcount(cbDestAddress) const struct sockaddr* pDestAddress, 434 | ULONG cbDestAddress, 435 | ULONG inboundReadLimit, 436 | ULONG outboundReadLimit, 437 | __in_bcount_opt(cbPrivateData) const VOID* pPrivateData, 438 | ULONG cbPrivateData, 439 | __inout OVERLAPPED* pOverlapped 440 | ) PURE; 441 | 442 | STDMETHOD(CompleteConnect)( 443 | THIS_ 444 | __inout OVERLAPPED* pOverlapped 445 | ) PURE; 446 | 447 | STDMETHOD(Accept)( 448 | THIS_ 449 | __in IUnknown* pQueuePair, 450 | ULONG inboundReadLimit, 451 | ULONG outboundReadLimit, 452 | __in_bcount_opt(cbPrivateData) const VOID* pPrivateData, 453 | ULONG cbPrivateData, 454 | __inout OVERLAPPED* pOverlapped 455 | ) PURE; 456 | 457 | STDMETHOD(Reject)( 458 | THIS_ 459 | __in_bcount_opt(cbPrivateData) const VOID* pPrivateData, 460 | ULONG cbPrivateData 461 | ) PURE; 462 | 463 | STDMETHOD(GetReadLimits)( 464 | THIS_ 465 | __out_opt ULONG* pInboundReadLimit, 466 | __out_opt ULONG* pOutboundReadLimit 467 | ) PURE; 468 | 469 | STDMETHOD(GetPrivateData)( 470 | THIS_ 471 | __out_bcount_opt(*pcbPrivateData) VOID* pPrivateData, 472 | __inout ULONG* pcbPrivateData 473 | ) PURE; 474 | 475 | STDMETHOD(GetLocalAddress)( 476 | THIS_ 477 | __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress, 478 | __inout ULONG* pcbAddress 479 | ) PURE; 480 | 481 | STDMETHOD(GetPeerAddress)( 482 | THIS_ 483 | __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress, 484 | __inout ULONG* pcbAddress 485 | ) PURE; 486 | 487 | STDMETHOD(NotifyDisconnect)( 488 | THIS_ 489 | __inout OVERLAPPED* pOverlapped 490 | ) PURE; 491 | 492 | STDMETHOD(Disconnect)( 493 | THIS_ 494 | __inout OVERLAPPED* pOverlapped 495 | ) PURE; 496 | }; 497 | 498 | 499 | // 500 | // Listener 501 | // 502 | #undef INTERFACE 503 | #define INTERFACE IND2Listener 504 | 505 | // {65D23D83-3A57-4E02-86A4-350165C2D130} 506 | DEFINE_GUID(IID_IND2Listener, 507 | 0x65d23d83, 0x3a57, 0x4e02, 0x86, 0xa4, 0x35, 0x1, 0x65, 0xc2, 0xd1, 0x30); 508 | 509 | DECLARE_INTERFACE_(IND2Listener, IND2Overlapped) 510 | { 511 | // *** IUnknown methods *** 512 | IFACEMETHOD(QueryInterface)( 513 | THIS_ 514 | REFIID riid, 515 | __deref_out LPVOID* ppvObj 516 | ) PURE; 517 | 518 | IFACEMETHOD_(ULONG,AddRef)( 519 | THIS 520 | ) PURE; 521 | 522 | IFACEMETHOD_(ULONG,Release)( 523 | THIS 524 | ) PURE; 525 | 526 | // *** IND2Overlapped methods *** 527 | IFACEMETHOD(CancelOverlappedRequests)( 528 | THIS 529 | ) PURE; 530 | 531 | IFACEMETHOD(GetOverlappedResult)( 532 | THIS_ 533 | __in OVERLAPPED* pOverlapped, 534 | bool wait 535 | ) PURE; 536 | 537 | // *** IND2Listen methods *** 538 | STDMETHOD(Bind)( 539 | THIS_ 540 | __in_bcount(cbAddress) const struct sockaddr* pAddress, 541 | ULONG cbAddress 542 | ) PURE; 543 | 544 | STDMETHOD(Listen)( 545 | THIS_ 546 | ULONG backlog 547 | ) PURE; 548 | 549 | STDMETHOD(GetLocalAddress)( 550 | THIS_ 551 | __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress, 552 | __inout ULONG* pcbAddress 553 | ) PURE; 554 | 555 | STDMETHOD(GetConnectionRequest)( 556 | THIS_ 557 | __inout IUnknown* pConnector, 558 | __inout OVERLAPPED* pOverlapped 559 | ) PURE; 560 | }; 561 | 562 | 563 | // 564 | // Adapter 565 | // 566 | #undef INTERFACE 567 | #define INTERFACE IND2Adapter 568 | 569 | // {D89C798C-4823-4D69-846C-DFDCCFF9E5F3} 570 | DEFINE_GUID(IID_IND2Adapter, 571 | 0xd89c798c, 0x4823, 0x4d69, 0x84, 0x6c, 0xdf, 0xdc, 0xcf, 0xf9, 0xe5, 0xf3); 572 | 573 | DECLARE_INTERFACE_(IND2Adapter, IUnknown) 574 | { 575 | // *** IUnknown methods *** 576 | IFACEMETHOD(QueryInterface)( 577 | THIS_ 578 | REFIID riid, 579 | __deref_out LPVOID* ppvObj 580 | ) PURE; 581 | 582 | IFACEMETHOD_(ULONG,AddRef)( 583 | THIS 584 | ) PURE; 585 | 586 | IFACEMETHOD_(ULONG,Release)( 587 | THIS 588 | ) PURE; 589 | 590 | // *** IND2Adapter methods *** 591 | STDMETHOD(CreateOverlappedFile)( 592 | THIS_ 593 | __deref_out HANDLE* phOverlappedFile 594 | ) PURE; 595 | 596 | STDMETHOD(Query)( 597 | THIS_ 598 | __inout_bcount_opt(*pcbInfo) ND2_ADAPTER_INFO* pInfo, 599 | __inout ULONG* pcbInfo 600 | ) PURE; 601 | 602 | STDMETHOD(QueryAddressList)( 603 | THIS_ 604 | __out_bcount_part_opt(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList, 605 | __inout ULONG* pcbAddressList 606 | ) PURE; 607 | 608 | STDMETHOD(CreateCompletionQueue)( 609 | THIS_ 610 | __in REFIID iid, 611 | __in HANDLE hOverlappedFile, 612 | ULONG queueDepth, 613 | USHORT group, 614 | KAFFINITY affinity, 615 | __deref_out VOID** ppCompletionQueue 616 | ) PURE; 617 | 618 | STDMETHOD(CreateMemoryRegion)( 619 | THIS_ 620 | __in REFIID iid, 621 | __in HANDLE hOverlappedFile, 622 | __deref_out VOID** ppMemoryRegion 623 | ) PURE; 624 | 625 | STDMETHOD(CreateMemoryWindow)( 626 | THIS_ 627 | __in REFIID iid, 628 | __deref_out VOID** ppMemoryWindow 629 | ) PURE; 630 | 631 | STDMETHOD(CreateSharedReceiveQueue)( 632 | THIS_ 633 | __in REFIID iid, 634 | __in HANDLE hOverlappedFile, 635 | ULONG queueDepth, 636 | ULONG maxRequestSge, 637 | ULONG notifyThreshold, 638 | USHORT group, 639 | KAFFINITY affinity, 640 | __deref_out VOID** ppSharedReceiveQueue 641 | ) PURE; 642 | 643 | STDMETHOD(CreateQueuePair)( 644 | THIS_ 645 | __in REFIID iid, 646 | __in IUnknown* pReceiveCompletionQueue, 647 | __in IUnknown* pInitiatorCompletionQueue, 648 | __in_opt VOID* context, 649 | ULONG receiveQueueDepth, 650 | ULONG initiatorQueueDepth, 651 | ULONG maxReceiveRequestSge, 652 | ULONG maxInitiatorRequestSge, 653 | ULONG inlineDataSize, 654 | __deref_out VOID** ppQueuePair 655 | ) PURE; 656 | 657 | STDMETHOD(CreateQueuePairWithSrq)( 658 | THIS_ 659 | __in REFIID iid, 660 | __in IUnknown* pReceiveCompletionQueue, 661 | __in IUnknown* pInitiatorCompletionQueue, 662 | __in IUnknown* pSharedReceiveQueue, 663 | __in_opt VOID* context, 664 | ULONG initiatorQueueDepth, 665 | ULONG maxInitiatorRequestSge, 666 | ULONG inlineDataSize, 667 | __deref_out VOID** ppQueuePair 668 | ) PURE; 669 | 670 | STDMETHOD(CreateConnector)( 671 | THIS_ 672 | __in REFIID iid, 673 | __in HANDLE hOverlappedFile, 674 | __deref_out VOID** ppConnector 675 | ) PURE; 676 | 677 | STDMETHOD(CreateListener)( 678 | THIS_ 679 | __in REFIID iid, 680 | __in HANDLE hOverlappedFile, 681 | __deref_out VOID** ppListener 682 | ) PURE; 683 | }; 684 | 685 | 686 | // 687 | // Provider 688 | // 689 | #undef INTERFACE 690 | #define INTERFACE IND2Provider 691 | 692 | // {49EAE6C1-76C4-46D0-8003-5C2EAA2C9A8E} 693 | DEFINE_GUID(IID_IND2Provider, 694 | 0x49eae6c1, 0x76c4, 0x46d0, 0x80, 0x3, 0x5c, 0x2e, 0xaa, 0x2c, 0x9a, 0x8e); 695 | 696 | DECLARE_INTERFACE_(IND2Provider, IUnknown) 697 | { 698 | // *** IUnknown methods *** 699 | IFACEMETHOD(QueryInterface)( 700 | THIS_ 701 | REFIID riid, 702 | __deref_out LPVOID* ppvObj 703 | ) PURE; 704 | 705 | IFACEMETHOD_(ULONG,AddRef)( 706 | THIS 707 | ) PURE; 708 | 709 | IFACEMETHOD_(ULONG,Release)( 710 | THIS 711 | ) PURE; 712 | 713 | // *** IND2Provider methods *** 714 | STDMETHOD(QueryAddressList)( 715 | THIS_ 716 | __out_bcount_part_opt(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList, 717 | __inout ULONG* pcbAddressList 718 | ) PURE; 719 | 720 | STDMETHOD(ResolveAddress)( 721 | THIS_ 722 | __in_bcount(cbAddress) const struct sockaddr* pAddress, 723 | ULONG cbAddress, 724 | __out UINT64* pAdapterId 725 | ) PURE; 726 | 727 | STDMETHOD(OpenAdapter)( 728 | THIS_ 729 | __in REFIID iid, 730 | UINT64 adapterId, 731 | __deref_out VOID** ppAdapter 732 | ) PURE; 733 | }; 734 | 735 | 736 | /////////////////////////////////////////////////////////////////////////////// 737 | // 738 | // HPC Pack 2008 SDK interface 739 | // 740 | /////////////////////////////////////////////////////////////////////////////// 741 | 742 | DECLARE_HANDLE(ND_MR_HANDLE); 743 | 744 | 745 | typedef struct _ND_ADAPTER_INFO1 746 | { 747 | UINT32 VendorId; 748 | UINT32 DeviceId; 749 | SIZE_T MaxInboundSge; 750 | SIZE_T MaxInboundRequests; 751 | SIZE_T MaxInboundLength; 752 | SIZE_T MaxOutboundSge; 753 | SIZE_T MaxOutboundRequests; 754 | SIZE_T MaxOutboundLength; 755 | SIZE_T MaxInlineData; 756 | SIZE_T MaxInboundReadLimit; 757 | SIZE_T MaxOutboundReadLimit; 758 | SIZE_T MaxCqEntries; 759 | SIZE_T MaxRegistrationSize; 760 | SIZE_T MaxWindowSize; 761 | SIZE_T LargeRequestThreshold; 762 | SIZE_T MaxCallerData; 763 | SIZE_T MaxCalleeData; 764 | 765 | } ND_ADAPTER_INFO1; 766 | #define ND_ADAPTER_INFO ND_ADAPTER_INFO1 767 | 768 | typedef struct _ND_RESULT 769 | { 770 | HRESULT Status; 771 | SIZE_T BytesTransferred; 772 | 773 | } ND_RESULT; 774 | 775 | #pragma pack( push, 1 ) 776 | typedef struct _ND_MW_DESCRIPTOR 777 | { 778 | UINT64 Base; // Network byte order 779 | UINT64 Length; // Network byte order 780 | UINT32 Token; // Network byte order 781 | 782 | } ND_MW_DESCRIPTOR; 783 | #pragma pack( pop ) 784 | 785 | typedef struct _ND_SGE 786 | { 787 | VOID* pAddr; 788 | SIZE_T Length; 789 | ND_MR_HANDLE hMr; 790 | 791 | } ND_SGE; 792 | 793 | // 794 | // Overlapped object 795 | // 796 | #undef INTERFACE 797 | #define INTERFACE INDOverlapped 798 | 799 | // {C859E15E-75E2-4fe3-8D6D-0DFF36F02442} 800 | DEFINE_GUID(IID_INDOverlapped, 801 | 0xc859e15e, 0x75e2, 0x4fe3, 0x8d, 0x6d, 0xd, 0xff, 0x36, 0xf0, 0x24, 0x42); 802 | 803 | DECLARE_INTERFACE_(INDOverlapped, IUnknown) 804 | { 805 | // *** IUnknown methods *** 806 | IFACEMETHOD(QueryInterface)( 807 | THIS_ 808 | REFIID riid, 809 | __deref_out LPVOID* ppvObj 810 | ) PURE; 811 | 812 | IFACEMETHOD_(ULONG,AddRef)( 813 | THIS 814 | ) PURE; 815 | 816 | IFACEMETHOD_(ULONG,Release)( 817 | THIS 818 | ) PURE; 819 | 820 | // *** INDOverlapped methods *** 821 | STDMETHOD(CancelOverlappedRequests)( 822 | THIS 823 | ) PURE; 824 | 825 | STDMETHOD(GetOverlappedResult)( 826 | THIS_ 827 | __inout OVERLAPPED *pOverlapped, 828 | __out SIZE_T *pNumberOfBytesTransferred, 829 | bool bWait 830 | ) PURE; 831 | }; 832 | 833 | 834 | // 835 | // Completion Queue 836 | // 837 | #undef INTERFACE 838 | #define INTERFACE INDCompletionQueue 839 | 840 | // {1245A633-2A32-473a-830C-E05D1F869D02} 841 | DEFINE_GUID(IID_INDCompletionQueue, 842 | 0x1245a633, 0x2a32, 0x473a, 0x83, 0xc, 0xe0, 0x5d, 0x1f, 0x86, 0x9d, 0x2); 843 | 844 | DECLARE_INTERFACE_(INDCompletionQueue, INDOverlapped) 845 | { 846 | // *** IUnknown methods *** 847 | IFACEMETHOD(QueryInterface)( 848 | THIS_ 849 | REFIID riid, 850 | __deref_out LPVOID* ppvObj 851 | ) PURE; 852 | 853 | IFACEMETHOD_(ULONG,AddRef)( 854 | THIS 855 | ) PURE; 856 | 857 | IFACEMETHOD_(ULONG,Release)( 858 | THIS 859 | ) PURE; 860 | 861 | // *** INDOverlapped methods *** 862 | IFACEMETHOD(CancelOverlappedRequests)( 863 | THIS 864 | ) PURE; 865 | 866 | IFACEMETHOD(GetOverlappedResult)( 867 | THIS_ 868 | __inout OVERLAPPED *pOverlapped, 869 | __out SIZE_T *pNumberOfBytesTransferred, 870 | bool bWait 871 | ) PURE; 872 | 873 | // *** INDCompletionQueue methods *** 874 | STDMETHOD(Resize)( 875 | THIS_ 876 | SIZE_T nEntries 877 | ) PURE; 878 | 879 | STDMETHOD(Notify)( 880 | THIS_ 881 | DWORD Type, 882 | __inout OVERLAPPED* pOverlapped 883 | ) PURE; 884 | 885 | STDMETHOD_(SIZE_T,GetResults)( 886 | THIS_ 887 | __out_ecount_part_opt(nResults,return) ND_RESULT* pResults[], 888 | SIZE_T nResults 889 | ) PURE; 890 | }; 891 | 892 | 893 | // 894 | // Remove View 895 | // 896 | #undef INTERFACE 897 | #define INTERFACE INDMemoryWindow 898 | 899 | // {070FE1F5-0AB5-4361-88DB-974BA704D4B9} 900 | DEFINE_GUID(IID_INDMemoryWindow, 901 | 0x70fe1f5, 0xab5, 0x4361, 0x88, 0xdb, 0x97, 0x4b, 0xa7, 0x4, 0xd4, 0xb9); 902 | 903 | DECLARE_INTERFACE_(INDMemoryWindow, IUnknown) 904 | { 905 | // *** IUnknown methods *** 906 | IFACEMETHOD(QueryInterface)( 907 | THIS_ 908 | REFIID riid, 909 | __deref_out LPVOID* ppvObj 910 | ) PURE; 911 | 912 | IFACEMETHOD_(ULONG,AddRef)( 913 | THIS 914 | ) PURE; 915 | 916 | IFACEMETHOD_(ULONG,Release)( 917 | THIS 918 | ) PURE; 919 | }; 920 | 921 | 922 | // 923 | // Endpoint 924 | // 925 | #undef INTERFACE 926 | #define INTERFACE INDEndpoint 927 | 928 | // {DBD00EAB-B679-44a9-BD65-E82F3DE12D1A} 929 | DEFINE_GUID(IID_INDEndpoint, 930 | 0xdbd00eab, 0xb679, 0x44a9, 0xbd, 0x65, 0xe8, 0x2f, 0x3d, 0xe1, 0x2d, 0x1a); 931 | 932 | DECLARE_INTERFACE_(INDEndpoint, IUnknown) 933 | { 934 | // *** IUnknown methods *** 935 | IFACEMETHOD(QueryInterface)( 936 | THIS_ 937 | REFIID riid, 938 | __deref_out LPVOID* ppvObj 939 | ) PURE; 940 | 941 | IFACEMETHOD_(ULONG,AddRef)( 942 | THIS 943 | ) PURE; 944 | 945 | IFACEMETHOD_(ULONG,Release)( 946 | THIS 947 | ) PURE; 948 | 949 | // *** INDEndpoint methods *** 950 | STDMETHOD(Flush)( 951 | THIS 952 | ) PURE; 953 | 954 | STDMETHOD_(void, StartRequestBatch)( 955 | THIS 956 | ) PURE; 957 | 958 | STDMETHOD_(void, SubmitRequestBatch)( 959 | THIS 960 | ) PURE; 961 | 962 | STDMETHOD(Send)( 963 | THIS_ 964 | __out ND_RESULT* pResult, 965 | __in_ecount_opt(nSge) const ND_SGE* pSgl, 966 | SIZE_T nSge, 967 | DWORD Flags 968 | ) PURE; 969 | 970 | STDMETHOD(SendAndInvalidate)( 971 | THIS_ 972 | __out ND_RESULT* pResult, 973 | __in_ecount_opt(nSge) const ND_SGE* pSgl, 974 | SIZE_T nSge, 975 | __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, 976 | DWORD Flags 977 | ) PURE; 978 | 979 | STDMETHOD(Receive)( 980 | THIS_ 981 | __out ND_RESULT* pResult, 982 | __in_ecount_opt(nSge) const ND_SGE* pSgl, 983 | SIZE_T nSge 984 | ) PURE; 985 | 986 | STDMETHOD(Bind)( 987 | THIS_ 988 | __out ND_RESULT* pResult, 989 | __in ND_MR_HANDLE hMr, 990 | __in INDMemoryWindow* pMw, 991 | __in_bcount(BufferSize) const void* pBuffer, 992 | SIZE_T BufferSize, 993 | DWORD Flags, 994 | __out ND_MW_DESCRIPTOR* pMwDescriptor 995 | ) PURE; 996 | 997 | STDMETHOD(Invalidate)( 998 | THIS_ 999 | __out ND_RESULT* pResult, 1000 | __in INDMemoryWindow* pMw, 1001 | DWORD Flags 1002 | ) PURE; 1003 | 1004 | STDMETHOD(Read)( 1005 | THIS_ 1006 | __out ND_RESULT* pResult, 1007 | __in_ecount_opt(nSge) const ND_SGE* pSgl, 1008 | SIZE_T nSge, 1009 | __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, 1010 | ULONGLONG Offset, 1011 | DWORD Flags 1012 | ) PURE; 1013 | 1014 | STDMETHOD(Write)( 1015 | THIS_ 1016 | __out ND_RESULT* pResult, 1017 | __in_ecount_opt(nSge) const ND_SGE* pSgl, 1018 | SIZE_T nSge, 1019 | __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, 1020 | ULONGLONG Offset, 1021 | DWORD Flags 1022 | ) PURE; 1023 | }; 1024 | 1025 | 1026 | // 1027 | // Connector 1028 | // 1029 | #undef INTERFACE 1030 | #define INTERFACE INDConnector 1031 | 1032 | // {1BCAF2D1-E274-4aeb-AC57-CD5D4376E0B7} 1033 | DEFINE_GUID(IID_INDConnector, 1034 | 0x1bcaf2d1, 0xe274, 0x4aeb, 0xac, 0x57, 0xcd, 0x5d, 0x43, 0x76, 0xe0, 0xb7); 1035 | 1036 | DECLARE_INTERFACE_(INDConnector, INDOverlapped) 1037 | { 1038 | // *** IUnknown methods *** 1039 | IFACEMETHOD(QueryInterface)( 1040 | THIS_ 1041 | REFIID riid, 1042 | __deref_out LPVOID* ppvObj 1043 | ) PURE; 1044 | 1045 | IFACEMETHOD_(ULONG,AddRef)( 1046 | THIS 1047 | ) PURE; 1048 | 1049 | IFACEMETHOD_(ULONG,Release)( 1050 | THIS 1051 | ) PURE; 1052 | 1053 | // *** INDOverlapped methods *** 1054 | IFACEMETHOD(CancelOverlappedRequests)( 1055 | THIS 1056 | ) PURE; 1057 | 1058 | IFACEMETHOD(GetOverlappedResult)( 1059 | THIS_ 1060 | __inout OVERLAPPED *pOverlapped, 1061 | __out SIZE_T *pNumberOfBytesTransferred, 1062 | bool bWait 1063 | ) PURE; 1064 | 1065 | // *** INDConnector methods *** 1066 | STDMETHOD(CreateEndpoint)( 1067 | THIS_ 1068 | __in INDCompletionQueue* pInboundCq, 1069 | __in INDCompletionQueue* pOutboundCq, 1070 | SIZE_T nInboundEntries, 1071 | SIZE_T nOutboundEntries, 1072 | SIZE_T nInboundSge, 1073 | SIZE_T nOutboundSge, 1074 | SIZE_T InboundReadLimit, 1075 | SIZE_T OutboundReadLimit, 1076 | __out_opt SIZE_T* pMaxInlineData, 1077 | __deref_out INDEndpoint** ppEndpoint 1078 | ) PURE; 1079 | 1080 | STDMETHOD(Connect)( 1081 | THIS_ 1082 | __in INDEndpoint* pEndpoint, 1083 | __in_bcount(AddressLength) const struct sockaddr* pAddress, 1084 | SIZE_T AddressLength, 1085 | INT Protocol, 1086 | USHORT LocalPort, 1087 | __in_bcount_opt(PrivateDataLength) const void* pPrivateData, 1088 | SIZE_T PrivateDataLength, 1089 | __inout OVERLAPPED* pOverlapped 1090 | ) PURE; 1091 | 1092 | STDMETHOD(CompleteConnect)( 1093 | THIS_ 1094 | __inout OVERLAPPED* pOverlapped 1095 | ) PURE; 1096 | 1097 | STDMETHOD(Accept)( 1098 | THIS_ 1099 | __in INDEndpoint* pEndpoint, 1100 | __in_bcount_opt(PrivateDataLength) const void* pPrivateData, 1101 | SIZE_T PrivateDataLength, 1102 | __inout OVERLAPPED* pOverlapped 1103 | ) PURE; 1104 | 1105 | STDMETHOD(Reject)( 1106 | THIS_ 1107 | __in_bcount_opt(PrivateDataLength) const void* pPrivateData, 1108 | SIZE_T PrivateDataLength 1109 | ) PURE; 1110 | 1111 | STDMETHOD(GetConnectionData)( 1112 | THIS_ 1113 | __out_opt SIZE_T* pInboundReadLimit, 1114 | __out_opt SIZE_T* pOutboundReadLimit, 1115 | __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, 1116 | __inout_opt SIZE_T* pPrivateDataLength 1117 | ) PURE; 1118 | 1119 | STDMETHOD(GetLocalAddress)( 1120 | THIS_ 1121 | __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, 1122 | __inout SIZE_T* pAddressLength 1123 | ) PURE; 1124 | 1125 | STDMETHOD(GetPeerAddress)( 1126 | THIS_ 1127 | __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, 1128 | __inout SIZE_T* pAddressLength 1129 | ) PURE; 1130 | 1131 | STDMETHOD(NotifyDisconnect)( 1132 | THIS_ 1133 | __inout OVERLAPPED* pOverlapped 1134 | ) PURE; 1135 | 1136 | STDMETHOD(Disconnect)( 1137 | THIS_ 1138 | __inout OVERLAPPED* pOverlapped 1139 | ) PURE; 1140 | }; 1141 | 1142 | 1143 | // 1144 | // Listen 1145 | // 1146 | #undef INTERFACE 1147 | #define INTERFACE INDListen 1148 | 1149 | // {BB902588-BA3F-4441-9FE1-3B6795E4E668} 1150 | DEFINE_GUID(IID_INDListen, 1151 | 0xbb902588, 0xba3f, 0x4441, 0x9f, 0xe1, 0x3b, 0x67, 0x95, 0xe4, 0xe6, 0x68); 1152 | 1153 | DECLARE_INTERFACE_(INDListen, INDOverlapped) 1154 | { 1155 | // *** IUnknown methods *** 1156 | IFACEMETHOD(QueryInterface)( 1157 | THIS_ 1158 | REFIID riid, 1159 | __deref_out LPVOID* ppvObj 1160 | ) PURE; 1161 | 1162 | IFACEMETHOD_(ULONG,AddRef)( 1163 | THIS 1164 | ) PURE; 1165 | 1166 | IFACEMETHOD_(ULONG,Release)( 1167 | THIS 1168 | ) PURE; 1169 | 1170 | // *** INDOverlapped methods *** 1171 | IFACEMETHOD(CancelOverlappedRequests)( 1172 | THIS 1173 | ) PURE; 1174 | 1175 | IFACEMETHOD(GetOverlappedResult)( 1176 | THIS_ 1177 | __inout OVERLAPPED *pOverlapped, 1178 | __out SIZE_T *pNumberOfBytesTransferred, 1179 | bool bWait 1180 | ) PURE; 1181 | 1182 | // *** INDListen methods *** 1183 | STDMETHOD(GetConnectionRequest)( 1184 | THIS_ 1185 | __inout INDConnector* pConnector, 1186 | __inout OVERLAPPED* pOverlapped 1187 | ) PURE; 1188 | }; 1189 | 1190 | 1191 | // 1192 | // INDAdapter 1193 | // 1194 | #undef INTERFACE 1195 | #define INTERFACE INDAdapter 1196 | 1197 | // {A023C5A0-5B73-43bc-8D20-33AA07E9510F} 1198 | DEFINE_GUID(IID_INDAdapter, 1199 | 0xa023c5a0, 0x5b73, 0x43bc, 0x8d, 0x20, 0x33, 0xaa, 0x7, 0xe9, 0x51, 0xf); 1200 | 1201 | DECLARE_INTERFACE_(INDAdapter, INDOverlapped) 1202 | { 1203 | // *** IUnknown methods *** 1204 | IFACEMETHOD(QueryInterface)( 1205 | THIS_ 1206 | REFIID riid, 1207 | __deref_out LPVOID* ppvObj 1208 | ) PURE; 1209 | 1210 | IFACEMETHOD_(ULONG,AddRef)( 1211 | THIS 1212 | ) PURE; 1213 | 1214 | IFACEMETHOD_(ULONG,Release)( 1215 | THIS 1216 | ) PURE; 1217 | 1218 | // *** INDOverlapped methods *** 1219 | IFACEMETHOD(CancelOverlappedRequests)( 1220 | THIS 1221 | ) PURE; 1222 | 1223 | IFACEMETHOD(GetOverlappedResult)( 1224 | THIS_ 1225 | __inout OVERLAPPED *pOverlapped, 1226 | __out SIZE_T *pNumberOfBytesTransferred, 1227 | bool bWait 1228 | ) PURE; 1229 | 1230 | // *** INDAdapter methods *** 1231 | STDMETHOD_(HANDLE,GetFileHandle)( 1232 | THIS 1233 | ) PURE; 1234 | 1235 | STDMETHOD(Query)( 1236 | THIS_ 1237 | DWORD VersionRequested, 1238 | __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo, 1239 | __inout_opt SIZE_T* pBufferSize 1240 | ) PURE; 1241 | 1242 | STDMETHOD(Control)( 1243 | THIS_ 1244 | DWORD IoControlCode, 1245 | __in_bcount_opt(InBufferSize) const void* pInBuffer, 1246 | SIZE_T InBufferSize, 1247 | __out_bcount_opt(OutBufferSize) void* pOutBuffer, 1248 | SIZE_T OutBufferSize, 1249 | __out SIZE_T* pBytesReturned, 1250 | __inout OVERLAPPED* pOverlapped 1251 | ) PURE; 1252 | 1253 | STDMETHOD(CreateCompletionQueue)( 1254 | THIS_ 1255 | SIZE_T nEntries, 1256 | __deref_out INDCompletionQueue** ppCq 1257 | ) PURE; 1258 | 1259 | STDMETHOD(RegisterMemory)( 1260 | THIS_ 1261 | __in_bcount(BufferSize) const void* pBuffer, 1262 | SIZE_T BufferSize, 1263 | __inout OVERLAPPED* pOverlapped, 1264 | __deref_out ND_MR_HANDLE* phMr 1265 | ) PURE; 1266 | 1267 | STDMETHOD(DeregisterMemory)( 1268 | THIS_ 1269 | __in ND_MR_HANDLE hMr, 1270 | __inout OVERLAPPED* pOverlapped 1271 | ) PURE; 1272 | 1273 | STDMETHOD(CreateMemoryWindow)( 1274 | THIS_ 1275 | __out ND_RESULT* pInvalidateResult, 1276 | __deref_out INDMemoryWindow** ppMw 1277 | ) PURE; 1278 | 1279 | STDMETHOD(CreateConnector)( 1280 | THIS_ 1281 | __deref_out INDConnector** ppConnector 1282 | ) PURE; 1283 | 1284 | STDMETHOD(Listen)( 1285 | THIS_ 1286 | SIZE_T Backlog, 1287 | INT Protocol, 1288 | USHORT Port, 1289 | __out_opt USHORT* pAssignedPort, 1290 | __deref_out INDListen** ppListen 1291 | ) PURE; 1292 | }; 1293 | 1294 | 1295 | // 1296 | // INDProvider 1297 | // 1298 | #undef INTERFACE 1299 | #define INTERFACE INDProvider 1300 | 1301 | // {0C5DD316-5FDF-47e6-B2D0-2A6EDA8D39DD} 1302 | DEFINE_GUID(IID_INDProvider, 1303 | 0xc5dd316, 0x5fdf, 0x47e6, 0xb2, 0xd0, 0x2a, 0x6e, 0xda, 0x8d, 0x39, 0xdd); 1304 | 1305 | DECLARE_INTERFACE_(INDProvider, IUnknown) 1306 | { 1307 | // *** IUnknown methods *** 1308 | IFACEMETHOD(QueryInterface)( 1309 | THIS_ 1310 | REFIID riid, 1311 | __deref_out LPVOID* ppvObj 1312 | ) PURE; 1313 | 1314 | IFACEMETHOD_(ULONG,AddRef)( 1315 | THIS 1316 | ) PURE; 1317 | 1318 | IFACEMETHOD_(ULONG,Release)( 1319 | THIS 1320 | ) PURE; 1321 | 1322 | // *** INDProvider methods *** 1323 | STDMETHOD(QueryAddressList)( 1324 | THIS_ 1325 | __out_bcount_part_opt(*pBufferSize, *pBufferSize) SOCKET_ADDRESS_LIST* pAddressList, 1326 | __inout SIZE_T* pBufferSize 1327 | ) PURE; 1328 | 1329 | STDMETHOD(OpenAdapter)( 1330 | THIS_ 1331 | __in_bcount(AddressLength) const struct sockaddr* pAddress, 1332 | SIZE_T AddressLength, 1333 | __deref_out INDAdapter** ppAdapter 1334 | ) PURE; 1335 | }; 1336 | 1337 | // 1338 | // Map version 1 error values to version 2. 1339 | // 1340 | #define ND_LOCAL_LENGTH ND_DATA_OVERRUN 1341 | #define ND_INVALIDATION_ERROR ND_INVALID_DEVICE_REQUEST 1342 | 1343 | #endif // _NDSPI_H_ 1344 | --------------------------------------------------------------------------------