diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /nfp | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'nfp')
29 files changed, 5576 insertions, 0 deletions
diff --git a/nfp/net/ReadMe.md b/nfp/net/ReadMe.md new file mode 100644 index 00000000..aeb2c630 --- /dev/null +++ b/nfp/net/ReadMe.md @@ -0,0 +1,11 @@ +Near-Field Proximity Sample Driver (UMDF Version 1) +=================================================== + +This sample demonstrates how to use User-Mode Driver Framework (UMDF) version 1 to write a near-field proximity driver. + +Typically, a near-field proximity driver would use near-field technologies such as Near Field Communication (NFC), TransferJet, or Bump. However, this sample uses a TCP/IPv6 network connection and a static configuration between two machines to simulate near-field interaction. + +Related technologies +-------------------- +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + diff --git a/nfp/net/driver/Connection.cpp b/nfp/net/driver/Connection.cpp new file mode 100644 index 00000000..1aed9008 --- /dev/null +++ b/nfp/net/driver/Connection.cpp @@ -0,0 +1,296 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Author: + + Travis Martin (TravM) 06-24-2010 + +--*/ +#include "internal.h" + +#include "Connection.tmh" + +HRESULT SetSocketIpv6Only(_In_ SOCKET socket, _In_ BOOL Ipv6Only); + +HRESULT SynchronousReadSocket(_In_ SOCKET Socket, _In_reads_bytes_(cbBuffer) PVOID pBuffer, _In_ DWORD cbBuffer) +{ + HRESULT hr = S_OK; + DWORD dwIgnore; + OVERLAPPED Overlapped; + ZeroMemory(&Overlapped, sizeof(Overlapped)); + if (!ReadFile((HANDLE)Socket, pBuffer, cbBuffer, &dwIgnore, &Overlapped)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING)) + { + if (!GetOverlappedResult((HANDLE)Socket, &Overlapped, &dwIgnore, TRUE)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + hr = S_OK; + } + } + } + return hr; +} + +//CConnection +// static +HRESULT CConnection::Create(_In_ IConnectionCallback* pCallback, _Outptr_ CConnection** ppConnection) +{ + CConnection* pConnection; + pConnection = new CConnection(pCallback); + HRESULT hr = (pConnection != NULL ? S_OK : E_OUTOFMEMORY); + if (SUCCEEDED(hr)) + { + *ppConnection = pConnection; + } + + return hr; +} + +void CConnection::Terminate() +{ + MethodEntry("void"); + + // Only want to terminate once + STATE PriorState = (STATE)(InterlockedExchange((long*)&_State, (long)TERMINATED)); + if (PriorState != TERMINATED) + { + // Graceful shutdown + shutdown(_Socket, SD_SEND); + + // Don't wait for threadpool callbacks when this thread is actually the threadpool callback + if (_ThreadpoolThreadId != GetCurrentThreadId()) + { + // Let the ReceiveThreadProc gracefully shutdown + WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false); + } + + SOCKET Socket = (SOCKET)InterlockedExchangePointer((PVOID*)&_Socket, (PVOID)INVALID_SOCKET); + if (Socket != INVALID_SOCKET) + { + closesocket(Socket); + } + } + + MethodReturnVoid(); +} + +/* 9C7D2C68-5AD8-4A14-BE20-F8741D60D100 */ +const GUID MAGIC_PACKET = + {0x9C7D2C68, 0x5AD8, 0x4A14, {0xBE, 0x20, 0xF8, 0x74, 0x1D, 0x60, 0xD1, 0x00}}; + +HRESULT CConnection::InitializeAsClient(_In_ BEGIN_PROXIMITY_ARGS* pArgs) +{ + pArgs->szName[MAX_PATH-1] = L'\0'; + + MethodEntry("pArgs->szName = '%S'", + pArgs->szName); + + // Open a TCP/IP Socket to the remote Network NearFieldProximity device + HRESULT hr = S_OK; + + _Socket = socket(AF_INET6, SOCK_STREAM, 0); + if (_Socket == INVALID_SOCKET) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + + if (SUCCEEDED(hr)) + { + hr = SetSocketIpv6Only(_Socket, FALSE); + } + + if (SUCCEEDED(hr)) + { + SOCKADDR_STORAGE LocalAddress = {}; + SOCKADDR_STORAGE RemoteAddress = {}; + DWORD cbLocalAddress = sizeof(LocalAddress); + DWORD cbRemoteAddress = sizeof(RemoteAddress); + timeval Timeout = {8, 0}; + if (!WSAConnectByName(_Socket, pArgs->szName, L"9299", + &cbLocalAddress, (SOCKADDR*)&LocalAddress, + &cbRemoteAddress, (SOCKADDR*)&RemoteAddress, &Timeout, NULL)) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + TraceErrorHR(hr, L"WSAConnectByName FAILED"); + } + } + + if (SUCCEEDED(hr)) + { + if (setsockopt(_Socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + } + + if (SUCCEEDED(hr)) + { + // Send the Magic Packet + if (send(_Socket, (char*)&MAGIC_PACKET, sizeof(MAGIC_PACKET), 0) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + + if (SUCCEEDED(hr)) + { + GUID MagicPacket = {}; + hr = SynchronousReadSocket(_Socket, &MagicPacket, sizeof(MagicPacket)); + if (SUCCEEDED(hr)) + { + if (memcmp(&MagicPacket, &MAGIC_PACKET, sizeof(MAGIC_PACKET)) != 0) + { + hr = E_FAIL; + } + } + } + + if (SUCCEEDED(hr)) + { + // This doesn't take the socket, because we're the client and already + // have the socket in _Socket. + hr = FinalizeEstablish(INVALID_SOCKET); + } + } + + + if (FAILED(hr)) + { + if (_Socket != INVALID_SOCKET) + { + // Abortive shutdown of the socket + closesocket(_Socket); + _Socket = INVALID_SOCKET; + } + } + + MethodReturnHR(hr); +} + +void CConnection::ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket) +{ + MethodEntry("..."); + + TraceASSERT(Socket != INVALID_SOCKET); + + HRESULT hr = S_OK; + if (memcmp(pMagicPacket, &MAGIC_PACKET, sizeof(MAGIC_PACKET)) != 0) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + // Send the MAGIC_PACKET + if (send(Socket, (char*)&MAGIC_PACKET, sizeof(MAGIC_PACKET), 0) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + } + + if (SUCCEEDED(hr)) + { + hr = FinalizeEstablish(Socket); + } + + if (FAILED(hr)) + { + // Abortive shutdown of the socket + closesocket(Socket); + } + + MethodReturnVoid(); +} + +HRESULT CConnection::FinalizeEstablish(_In_ SOCKET Socket) +{ + MethodEntry("..."); + + HRESULT hr = S_OK; + STATE PriorState = (STATE)(InterlockedCompareExchange((long*)&_State, (long)ESTABLISHED, (long)INITIAL)); + if (PriorState != INITIAL) + { + // Already established (or terminated), drop this + hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED); + } + + if (SUCCEEDED(hr)) + { + // Init Threadpool work item for the receieve thread proc. + _ThreadpoolWork = CreateThreadpoolWork(s_ReceiveThreadProc, this, NULL); + if (_ThreadpoolWork == NULL) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + if (Socket != INVALID_SOCKET) + { + // Take ownership of the socket + _Socket = Socket; + } + SubmitThreadpoolWork(_ThreadpoolWork); + + _pCallback->ConnectionEstablished(this); + } + } + + MethodReturnHR(hr); +} + +BOOL CConnection::ReceiveThreadProc() +{ + MethodEntry("void"); + + MESSAGE* pMessage = new MESSAGE(); + if (pMessage == NULL) + { + Terminate(); + } + else + { + while (_Socket != INVALID_SOCKET) + { + if (recv(_Socket, (char*)pMessage, sizeof(*pMessage), MSG_WAITALL) == sizeof(*pMessage)) + { + _pCallback->HandleReceivedMessage(pMessage); + } + else + { + Terminate(); + break; + } + } + delete pMessage; + } + + // The connection is now terminated + BOOL fConnectionDeleted = _pCallback->ConnectionTerminated(this); + + MethodReturnBool(fConnectionDeleted); +} + +HRESULT CConnection::TransmitMessage(_In_ MESSAGE* pMessage) +{ + HRESULT hr = S_OK; + if (_Socket == INVALID_SOCKET) + { + hr = HRESULT_FROM_WIN32(WSAENOTSOCK); + } + else + { + if (send(_Socket, (char*)pMessage, sizeof(*pMessage), 0) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + Terminate(); + } + } + + return hr; +} + diff --git a/nfp/net/driver/FileContext.cpp b/nfp/net/driver/FileContext.cpp new file mode 100644 index 00000000..193c637a --- /dev/null +++ b/nfp/net/driver/FileContext.cpp @@ -0,0 +1,713 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + filecontext.cpp + +Abstract: + + This file implements the class for context associated with the file object + +Environment: + + user mode only + +Revision History: + +--*/ +#include "internal.h" + +#include "FileContext.tmh" + +CFileContext::~CFileContext() +{ + MethodEntry("void"); + + while (!IsListEmpty(&m_SubscribedMessageQueue)) + { + delete CMyPayload::FromListEntry(RemoveHeadList(&m_SubscribedMessageQueue)); + } + + if (m_pszType != NULL) + { + delete [] m_pszType; + m_pszType = NULL; + } + + if (m_pConnection != NULL) + { + delete m_pConnection; + m_pConnection = NULL; + } + + m_pWdfFile = NULL; + + EnterCriticalSection(&m_RoleLock); + CompleteRequest(E_ABORT, 0, true); + LeaveCriticalSection(&m_RoleLock); + + DeleteCriticalSection(&m_RoleLock); + + MethodReturnVoid(); +} + +HRESULT +CFileContext::Disable() +{ + MethodEntry("void"); + + EnterCriticalSection(&m_RoleLock); + + HRESULT hr = S_OK; + if ((m_Role == ROLE_UNDEFINED) || (m_Role == ROLE_PROXIMITY)) + { + // Only Pub/Sub handles can be disabled + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (!m_fEnabled) + { + // Already disabled + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (SUCCEEDED(hr)) + { + m_fEnabled = FALSE; + + CompleteRequest(HRESULT_FROM_NT(STATUS_CANCELLED), 0, true); + + // Purge all already received payloads + while (!IsListEmpty(&m_SubscribedMessageQueue)) + { + delete CMyPayload::FromListEntry(RemoveHeadList(&m_SubscribedMessageQueue)); + } + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnHR(hr); +} + +HRESULT +CFileContext::Enable() +{ + MethodEntry("void"); + + EnterCriticalSection(&m_RoleLock); + + HRESULT hr = S_OK; + if ((m_Role == ROLE_UNDEFINED) || (m_Role == ROLE_PROXIMITY)) + { + // Only Pub/Sub handles can be enabled + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (m_fEnabled) + { + // Already enabled + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (SUCCEEDED(hr)) + { + m_fEnabled = TRUE; + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnHR(hr); +} + +HRESULT +CFileContext::SetType(_In_ PCWSTR pszType) +{ + MethodEntry("pszType = '%S'", pszType); + + HRESULT hr = S_OK; + WUDF_SAMPLE_DRIVER_ASSERT(m_pszType == NULL); + + SIZE_T cchStr = wcslen(pszType) + 1; + if ((cchStr > MinCchType) && (cchStr < MaxCchType)) + { + m_pszType = new WCHAR[cchStr]; + if (m_pszType != NULL) + { + hr = StringCchCopy(m_pszType, cchStr, pszType); + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_INVALIDARG; + } + + MethodReturnHR(hr); +} + +#define STATUS_BUFFER_TOO_SMALL 0xC0000023L +#define STATUS_BUFFER_OVERFLOW 0x80000005L + + +bool +CFileContext::CompleteOneGetNextSubscribedMessage( + _In_ DWORD cbPayload, + _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload + ) +/* + * m_RoleLock must already be acquired + */ +{ + MethodEntry("cbPayload = 0x%d", + (DWORD)cbPayload); + + WUDF_SAMPLE_DRIVER_ASSERT(m_pWdfRequest != NULL); + + bool fDelivered = false; + IWDFMemory* pWdfOutputMemory; + m_pWdfRequest->GetOutputMemory(&pWdfOutputMemory); + if (pWdfOutputMemory != NULL) + { + SIZE_T cbOutputBuffer = 0; + // Set the first 4 bytes as the size of the payload as a hint for future + // subscriptions. + HRESULT hr = pWdfOutputMemory->CopyFromBuffer(0, &cbPayload, 4); + if (SUCCEEDED(hr)) + { + cbOutputBuffer = 4; + if (pbPayload != NULL) + { + if (pWdfOutputMemory->GetSize() < (cbPayload + 4)) + { + // We are unable to copy the payload into the output memory, + // Returning this signals to the client to send a bigger buffer + hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW); + } + else + { + hr = pWdfOutputMemory->CopyFromBuffer(4, pbPayload, cbPayload); + } + } + + if (SUCCEEDED(hr)) + { + fDelivered = true; + cbOutputBuffer += cbPayload; + if (m_dwQueueSize > 0) + { + m_dwQueueSize--; + } + } + } + pWdfOutputMemory->Release(); + + if (!CompleteRequest(hr, cbOutputBuffer, true)) + { + fDelivered = false; + } + } + + MethodReturnBool(fDelivered); +} + +HRESULT +CFileContext::GetNextSubscribedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest) +{ + MethodEntry("..."); + + EnterCriticalSection(&m_RoleLock); + + HRESULT hr = S_OK; + if (m_pWdfRequest != NULL) + { + // Only one pended request at a time allowed + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (!m_fEnabled) + { + // The handle is disabled + hr = HRESULT_FROM_NT(HRESULT_FROM_NT(STATUS_CANCELLED)); + } + + if (SUCCEEDED(hr)) + { + IWDFMemory* pWdfInputMemory; + pWdfRequest->GetInputMemory(&pWdfInputMemory); + SIZE_T cbInput; + if (pWdfInputMemory->GetDataBuffer(&cbInput) == NULL) + { + if (m_Role == ROLE_SUBSCRIPTION) + { + m_pWdfRequest = pWdfRequest; + m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread + + if ((m_pWdfRequest != NULL) && !IsListEmpty(&m_SubscribedMessageQueue)) + { + CMyPayload* pMyPayload = + CMyPayload::FromListEntry(m_SubscribedMessageQueue.Flink); + + if (CompleteOneGetNextSubscribedMessage(pMyPayload->GetSize(), + pMyPayload->GetPayload())) + { + RemoveHeadList(&m_SubscribedMessageQueue); + delete pMyPayload; + } + } + } + else if (m_Role == ROLE_ARRIVEDSUBSCRIPTION) + { + m_pWdfRequest = pWdfRequest; + m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread + if (m_pWdfRequest != NULL) + { + CompleteOneArrivalEvent(); + } + } + else if (m_Role == ROLE_DEPARTEDSUBSCRIPTION) + { + m_pWdfRequest = pWdfRequest; + m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread + if (m_pWdfRequest != NULL) + { + CompleteOneRemovalEvent(); + } + } + else + { + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + } + else + { + hr = E_INVALIDARG; + } + pWdfInputMemory->Release(); + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnHR(hr); +} + +HRESULT +CFileContext::SetPayload(_In_ IWDFIoRequest* pWdfRequest) +{ + MethodEntry("..."); + + EnterCriticalSection(&m_RoleLock); + + HRESULT hr = S_OK; + if ((m_Role != ROLE_PUBLICATION) || (m_MyPayload.GetPayload() != NULL)) + { + // SetPayload can only be called once per handle + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (SUCCEEDED(hr)) + { + IWDFMemory* pWdfOutputMemory; + pWdfRequest->GetOutputMemory(&pWdfOutputMemory); + SIZE_T cbOutput; + if (pWdfOutputMemory->GetDataBuffer(&cbOutput) == NULL) + { + IWDFMemory* pWdfMemory; + pWdfRequest->GetInputMemory(&pWdfMemory); + if (pWdfMemory != NULL) + { + SIZE_T cbPayload = pWdfMemory->GetSize(); + if ((cbPayload > 0) && (cbPayload <= MaxCbPayload)) + { + hr = m_MyPayload.Initialize((DWORD)cbPayload, (PBYTE)pWdfMemory->GetDataBuffer(NULL)); + } + else + { + hr = HRESULT_FROM_NT(STATUS_INVALID_BUFFER_SIZE); + } + + pWdfMemory->Release(); + } + else + { + hr = E_INVALIDARG; + } + pWdfOutputMemory->Release(); + } + else + { + hr = E_INVALIDARG; + } + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnHR(hr); +} + +HRESULT +CFileContext::GetNextTransmittedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest) +{ + MethodEntry("..."); + + EnterCriticalSection(&m_RoleLock); + + HRESULT hr = S_OK; + if ((m_Role != ROLE_PUBLICATION) || (m_pWdfRequest != NULL)) + { + // Only one pended request at a time allowed + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + + if (!m_fEnabled) + { + // The handle is disabled + hr = HRESULT_FROM_NT(HRESULT_FROM_NT(STATUS_CANCELLED)); + } + + if (SUCCEEDED(hr)) + { + IWDFMemory* pWdfInputMemory; + pWdfRequest->GetInputMemory(&pWdfInputMemory); + SIZE_T cbInput; + if (pWdfInputMemory->GetDataBuffer(&cbInput) == NULL) + { + IWDFMemory* pWdfOutputMemory; + pWdfRequest->GetOutputMemory(&pWdfOutputMemory); + SIZE_T cbOutput; + if (pWdfOutputMemory->GetDataBuffer(&cbOutput) == NULL) + { + m_pWdfRequest = pWdfRequest; + + if (m_cCompleteReady > 0) + { + if (CompleteRequest(S_OK, 0, false)) + { + m_cCompleteReady--; + } + } + } + else + { + hr = E_INVALIDARG; + } + pWdfOutputMemory->Release(); + } + else + { + hr = E_INVALIDARG; + } + pWdfInputMemory->Release(); + } + + if (SUCCEEDED(hr) && (m_pWdfRequest != NULL)) + { + m_pWdfRequest->MarkCancelable(pCallbackCancel); + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnHR(hr); +} + +HRESULT +CFileContext::BeginProximity( + _In_ IWDFIoRequest* pWdfRequest, + _In_ IConnectionCallback* pCallback + ) +{ + MethodEntry("..."); + + EnterCriticalSection(&m_RoleLock); + + HRESULT hr = S_OK; + if (m_Role != ROLE_UNDEFINED) + { + // BeginProximity can only be called once per handle + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + } + else + { + m_Role = ROLE_PROXIMITY; + } + + LeaveCriticalSection(&m_RoleLock); + + if (SUCCEEDED(hr)) + { + IWDFMemory* pWdfMemory; + pWdfRequest->GetInputMemory(&pWdfMemory); + if (pWdfMemory != NULL) + { + if (pWdfMemory->GetSize() == sizeof(BEGIN_PROXIMITY_ARGS)) + { + hr = CConnection::Create(pCallback, &m_pConnection); + if (SUCCEEDED(hr)) + { + BEGIN_PROXIMITY_ARGS* pArgs = + (BEGIN_PROXIMITY_ARGS*)pWdfMemory->GetDataBuffer(NULL); + hr = m_pConnection->InitializeAsClient(pArgs); + } + } + else + { + hr = E_INVALIDARG; + } + + pWdfMemory->Release(); + } + else + { + hr = E_INVALIDARG; + } + } + + + if (FAILED(hr)) + { + m_pConnection = NULL; + } + + MethodReturnHR(hr); +} + +VOID +CFileContext::HandleArrivalEvent() +{ + WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_ARRIVEDSUBSCRIPTION); + + EnterCriticalSection(&m_RoleLock); + + if (m_fEnabled) + { + m_cCompleteReady++; + CompleteOneArrivalEvent(); + } + + LeaveCriticalSection(&m_RoleLock); +} + +VOID +CFileContext::HandleRemovalEvent() +{ + WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_DEPARTEDSUBSCRIPTION); + + EnterCriticalSection(&m_RoleLock); + + if (m_fEnabled) + { + m_cCompleteReady++; + CompleteOneRemovalEvent(); + } + + LeaveCriticalSection(&m_RoleLock); +} + +VOID +CFileContext::CompleteOneArrivalEvent() +{ + MethodEntry("void"); + + WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_ARRIVEDSUBSCRIPTION); + + EnterCriticalSection(&m_RoleLock); + + if (m_cCompleteReady > 0) + { + if (m_pWdfRequest != NULL) + { + // Arrival payload should either be a DWORD = 1 or 0 + // 1 == Device capable of bi-directional communication + // 0 == Device is a dumb tag + DWORD ArrivalFlags = 0x1; + if (CompleteOneGetNextSubscribedMessage(sizeof(ArrivalFlags), (PBYTE)&ArrivalFlags)) + { + m_cCompleteReady--; + } + } + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnVoid(); +} + +VOID +CFileContext::CompleteOneRemovalEvent() +{ + MethodEntry("void"); + + WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_DEPARTEDSUBSCRIPTION); + + EnterCriticalSection(&m_RoleLock); + + if (m_cCompleteReady > 0) + { + if (m_pWdfRequest != NULL) + { + // Removal payload should be a single zeroed DWORD + DWORD RemovalFlags = 0x0; + if (CompleteOneGetNextSubscribedMessage(sizeof(RemovalFlags), (PBYTE)&RemovalFlags)) + { + m_cCompleteReady--; + } + } + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnVoid(); +} + +void +CFileContext::HandleReceivedPublication( + _In_ PCWSTR pszType, + _In_ DWORD cbPayload, + _In_reads_bytes_(cbPayload) PBYTE pbPayload + ) +{ + MethodEntry("..."); + + WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_SUBSCRIPTION); + + EnterCriticalSection(&m_RoleLock); + + if (m_fEnabled) + { + bool fSubscriptionMatches = false; + BYTE* pbNewPayload = NULL; + + if ((CompareStringOrdinal(m_pszType, -1, WINDOWSMIME_PROTOCOL, -1, FALSE) == CSTR_EQUAL) && + (wcslen(pszType) > WINDOWSMIME_PROTOCOL_CHARS) && + (CompareStringOrdinal(pszType, WINDOWSMIME_PROTOCOL_CHARS, + WINDOWSMIME_PROTOCOL, -1, FALSE) == CSTR_EQUAL)) + { + // If this is a WindowsMime message, and the subscription is for the general WINDOWSMIME_PROTOCOL type, + // the Mime type needs to be added to the message payload. + CHAR szMimeType[MaxCchMimeType + 1] = {}; + // Copy the mime type and convert from wide to multibyte chars + if (SUCCEEDED(StringCchPrintfA(szMimeType, ARRAYSIZE(szMimeType), "%S", pszType + WINDOWSMIME_PROTOCOL_CHARS + 1))) + { + pbNewPayload = new BYTE[cbPayload + MaxCchMimeType]; + if (pbNewPayload != NULL) + { + TraceInfo("Received Mime message of type = '%s'", szMimeType); + CopyMemory(pbNewPayload, szMimeType, MaxCchMimeType); + CopyMemory(pbNewPayload + MaxCchMimeType, pbPayload, cbPayload); + cbPayload += MaxCchMimeType; + pbPayload = pbNewPayload; + + fSubscriptionMatches = true; + } + } + } + else if (CompareStringOrdinal(pszType, -1, m_pszType, -1, FALSE) == CSTR_EQUAL) + { + fSubscriptionMatches = true; + } + + if (fSubscriptionMatches) + { + bool fDelivered = false; + + if (m_pWdfRequest != NULL) + { + fDelivered = CompleteOneGetNextSubscribedMessage(cbPayload, pbPayload); + } + + if ((!fDelivered) && (m_dwQueueSize < MAX_MESSAGE_QUEUE_SIZE)) + { + // Add message to the client delivery queue + + CMyPayload* pMyPayload = new CMyPayload(); + if (pMyPayload) + { + if (SUCCEEDED(pMyPayload->Initialize(cbPayload, pbPayload))) + { + InsertTailList(&m_SubscribedMessageQueue, pMyPayload->GetListEntry()); + m_dwQueueSize++; + } + else + { + delete pMyPayload; + } + } + } + } + + delete [] pbNewPayload; + } + else + { + TraceErrorHR(HRESULT_FROM_NT(STATUS_CANCELLED), "Subscription Disabled!"); + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnVoid(); +} + +void +CFileContext::HandleMessageTransmitted() +{ + MethodEntry("void"); + + WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_PUBLICATION); + + EnterCriticalSection(&m_RoleLock); + + if (!CompleteRequest(S_OK, 0, true)) + { + m_cCompleteReady++; + } + + LeaveCriticalSection(&m_RoleLock); + + MethodReturnVoid(); +} + +void +CFileContext::OnCancel() +{ + EnterCriticalSection(&m_RoleLock); + + CompleteRequest(E_ABORT, 0, false); + + LeaveCriticalSection(&m_RoleLock); +} + +bool +CFileContext::CompleteRequest(_In_ HRESULT hr, _In_ SIZE_T cbSize, _In_ bool fIsCancelable) +/* + * m_RoleLock must already be acquired + */ +{ + MethodEntry("hr = %!HRESULT!, cbSize = %d, fIsCancelable = %!bool!", + hr, (DWORD)cbSize, fIsCancelable); + + bool fCompleted = false; + if (m_pWdfRequest != NULL) + { + bool fCompleteRequest = true; + if (fIsCancelable) + { + if (m_pWdfRequest->UnmarkCancelable() == HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)) + { + fCompleteRequest = false; + } + } + + if (fCompleteRequest) + { + m_pWdfRequest->CompleteWithInformation(hr, cbSize); + m_pWdfRequest = NULL; + fCompleted = true; + } + } + + MethodReturnBool(fCompleted); +} diff --git a/nfp/net/driver/FileContext.h b/nfp/net/driver/FileContext.h new file mode 100644 index 00000000..0247636e --- /dev/null +++ b/nfp/net/driver/FileContext.h @@ -0,0 +1,340 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + filecontext.h + +Abstract: + + This header file defines the structure type for context associated with the file object + +Environment: + + user mode only + +Revision History: + +--*/ +#pragma once + +class CMyPayload +{ +public: + CMyPayload() + { + m_pbPayload = NULL; + m_cbPayload = 0; + + InitializeListHead(&m_ListEntry); + } + ~CMyPayload() + { + if (m_pbPayload != NULL) + { + delete [] m_pbPayload; + m_pbPayload = NULL; + } + } + + STDMETHOD(Initialize)( + _In_ DWORD cbPayload, + _In_reads_bytes_(cbPayload) PBYTE pbPayload + ) + { + HRESULT hr = S_OK; + m_pbPayload = new BYTE[cbPayload]; + if (m_pbPayload != NULL) + { + m_cbPayload = cbPayload; + CopyMemory(m_pbPayload, pbPayload, cbPayload); + } + else + { + hr = E_OUTOFMEMORY; + } + + return hr; + } + + PBYTE GetPayload() + { + return m_pbPayload; + } + DWORD GetSize() + { + return m_cbPayload; + } + + PLIST_ENTRY GetListEntry() + { + return &m_ListEntry; + } + static CMyPayload* FromListEntry(PLIST_ENTRY pEntry) + { + return (CMyPayload*) CONTAINING_RECORD(pEntry, CMyPayload, m_ListEntry); + } + +private: + PBYTE m_pbPayload; + DWORD m_cbPayload; + + LIST_ENTRY m_ListEntry; +}; + +/* + * Use this to refactor to only keep one copy of received messages + * +class CMyPayloadItem +{ +public: + CMyPayloadItem(_In_ CMyPayload* pPayload) + { + m_spPayload = pPayload; + InitializeListHead(&m_ListEntry); + } + ~CMyPayloadItem() + { + } + + PBYTE GetPayload() + { + return m_spPayload->GetPayload(); + } + DWORD GetSize() + { + return m_spPayload->GetSize(); + } + + PLIST_ENTRY GetListEntry() + { + return &m_ListEntry; + } + static CMyPayloadItem* FromListEntry(PLIST_ENTRY pEntry) + { + return (CMyPayloadItem*) CONTAINING_RECORD(pEntry, CMyPayloadItem, m_ListEntry); + } + +private: + CComPtr<CMyPayload> m_spPayload; + + LIST_ENTRY m_ListEntry; +}; +*/ + +class CFileContext +{ +public: + + CFileContext() : + m_Role(ROLE_UNDEFINED), + m_pszType(NULL), + m_fEnabled(TRUE), + m_dwQueueSize(0), + m_cCompleteReady(0), + m_pConnection(NULL), + m_pWdfRequest(NULL) + { + InitializeListHead(&m_SubscribedMessageQueue); + + InitializeListHead(&m_ListEntry); + + InitializeCriticalSection(&m_RoleLock); + } + + ~CFileContext(); + + HRESULT + Disable(); + + HRESULT + Enable(); + + HRESULT + SetType(_In_ PCWSTR pszType); + + HRESULT + GetNextSubscribedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest); + + HRESULT + SetPayload(_In_ IWDFIoRequest* pWdfRequest); + + HRESULT + GetNextTransmittedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest); + + HRESULT + BeginProximity( + _In_ IWDFIoRequest* pWdfRequest, + _In_ IConnectionCallback* pCallback + ); + + VOID + HandleArrivalEvent(); + VOID + HandleRemovalEvent(); + + void + HandleReceivedPublication( + _In_ PCWSTR pszType, + _In_ DWORD cbPayload, + _In_reads_bytes_(cbPayload) PBYTE pbPayload + ); + + void + HandleMessageTransmitted(); + + void + OnCancel(); + + void + SetRoleSubcription() + { + m_Role = ROLE_SUBSCRIPTION; + } + + void + SetRolePublication() + { + m_Role = ROLE_PUBLICATION; + } + + BOOL + SetRoleArrivedSubcription() + { + if (m_Role == ROLE_SUBSCRIPTION) + { + m_Role = ROLE_ARRIVEDSUBSCRIPTION; + return TRUE; + } + return FALSE; + } + + BOOL + SetRoleDepartedSubcription() + { + if (m_Role == ROLE_SUBSCRIPTION) + { + m_Role = ROLE_DEPARTEDSUBSCRIPTION; + return TRUE; + } + return FALSE; + } + + BOOL + IsNormalSubscription() + { + return (m_Role == ROLE_SUBSCRIPTION); + } + BOOL + IsArrivedSubscription() + { + return (m_Role == ROLE_ARRIVEDSUBSCRIPTION); + } + BOOL + IsDepartedSubscription() + { + return (m_Role == ROLE_DEPARTEDSUBSCRIPTION); + } + BOOL + IsSubscription() + { + return (m_Role == ROLE_SUBSCRIPTION); + } + BOOL + IsPublication() + { + return (m_Role == ROLE_PUBLICATION); + } + + PCWSTR + GetType() + { + return m_pszType; + } + + DWORD + GetSize() + { + return m_MyPayload.GetSize(); + } + + PBYTE + GetPayload() + { + return m_MyPayload.GetPayload(); + } + + BOOL + IsEnabled() + { + return m_fEnabled; + } + + PLIST_ENTRY GetListEntry() + { + return &m_ListEntry; + } + static CFileContext* FromListEntry(PLIST_ENTRY pEntry) + { + return (CFileContext*) CONTAINING_RECORD(pEntry, CFileContext, m_ListEntry); + } + +private: + + VOID + CompleteOneArrivalEvent(); + VOID + CompleteOneRemovalEvent(); + + bool + CompleteOneGetNextSubscribedMessage( + _In_ DWORD cbPayload, + _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload + ); + + bool + CompleteRequest( + _In_ HRESULT hr, + _In_ SIZE_T cbSize, + _In_ bool fIsCancelable + ); + +private: + + enum ROLE + { + ROLE_UNDEFINED, + ROLE_SUBSCRIPTION, + ROLE_ARRIVEDSUBSCRIPTION, + ROLE_DEPARTEDSUBSCRIPTION, + ROLE_PUBLICATION, + ROLE_PROXIMITY + }; + + ROLE m_Role; + + PWSTR m_pszType; + + BOOL m_fEnabled; + + DWORD m_dwQueueSize; + + // Queue of received messages + LIST_ENTRY m_SubscribedMessageQueue; // Unique to ROLE_SUBSCRIPTION + + CMyPayload m_MyPayload; // Unique to ROLE_PUBLICATION + SIZE_T m_cCompleteReady; // Unique to ROLE_PUBLICATION, ROLE_ARRIVEDSUBSCRIPTION, and ROLE_DEPARTEDSUBSCRIPTION + + CConnection* m_pConnection; // Unique to ROLE_PROXIMITY + + // Pended "Get Next" Request. + IWDFIoRequest* m_pWdfRequest; + + // The Fx File object this CFileObject is a companion to + IWDFFile* m_pWdfFile; + + CRITICAL_SECTION m_RoleLock; + + LIST_ENTRY m_ListEntry; +}; diff --git a/nfp/net/driver/NetNfpProvider.vcxproj b/nfp/net/driver/NetNfpProvider.vcxproj new file mode 100644 index 00000000..da21fa09 --- /dev/null +++ b/nfp/net/driver/NetNfpProvider.vcxproj @@ -0,0 +1,265 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{756016BF-4187-4482-A0BE-CEE1698BD129}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{9E5FA410-9825-4FD4-845A-FFEDEE9AF94B}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllsup.cpp; driver.cpp; device.cpp; queue.cpp; connection.cpp; FileContext.cpp; SocketListener.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="NetNfpProvider.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <Verbose>true</Verbose> + <CopyOutput>.\$(IntDir)\NetNfpProvider.inf</CopyOutput> + </Inf> + <OtherWpp Include="NetNfpProvider.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>NetNfpProvider</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>NetNfpProvider</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>NetNfpProvider</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>NetNfpProvider</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="NetNfpProvider.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/nfp/net/driver/NetNfpProvider.vcxproj.Filters b/nfp/net/driver/NetNfpProvider.vcxproj.Filters new file mode 100644 index 00000000..cfe106d2 --- /dev/null +++ b/nfp/net/driver/NetNfpProvider.vcxproj.Filters @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{1A46FC37-1F58-4A1C-AD58-4C8F0BFF8004}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{558A638D-8A37-44D7-BB58-296F1AEE8066}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{06C2D74D-F153-45FD-9B8F-09D1A0CD979F}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{D6F88F8A-6CD0-44DA-BC07-EEFF2E791D12}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="connection.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="FileContext.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SocketListener.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\NetNfpProvider.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="NetNfpProvider.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="NetNfpProvider.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/nfp/net/driver/Queue.cpp b/nfp/net/driver/Queue.cpp new file mode 100644 index 00000000..129a5439 --- /dev/null +++ b/nfp/net/driver/Queue.cpp @@ -0,0 +1,824 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + user mode only + +Revision History: + +--*/ +#include "internal.h" + +#include "queue.tmh" + +CMyQueue::CMyQueue( + VOID + ) +{ + InitializeListHead(&m_SubsHead); + InitializeListHead(&m_ArrivalSubsHead); + InitializeListHead(&m_DepartureSubsHead); + InitializeListHead(&m_PubsHead); + InitializeListHead(&m_ConnectionHead); + + InitializeCriticalSection(&m_SubsLock); + InitializeCriticalSection(&m_PubsLock); + InitializeCriticalSection(&m_ConnectionLock); +} + +CMyQueue::~CMyQueue( + VOID + ) +{ + MethodEntry("void"); + + m_SocketListener.StopAccepting(); + + while (!IsListEmpty(&m_ConnectionHead)) + { + delete CConnection::FromListEntry(RemoveHeadList(&m_ConnectionHead)); + } + + DeleteCriticalSection(&m_SubsLock); + DeleteCriticalSection(&m_PubsLock); + DeleteCriticalSection(&m_ConnectionLock); +} + +// +// Initialize +// + +HRESULT +CMyQueue::Initialize( + _In_ CMyDevice * Device + ) +/*++ + +Routine Description: + + Queue Initialize helper routine. + This routine will Create a default parallel queue associated with the Fx device object + and pass the IUnknown for this queue + +Aruments: + Device object pointer + +Return Value: + + S_OK if Initialize succeeds + +--*/ +{ + MethodEntry("..."); + + CComPtr<IWDFIoQueue> fxQueue; + + HRESULT hr; + + // + // Create the I/O Queue object. + // + { + CComPtr<IUnknown> pUnk; + + HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk); + + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + hr = Device->GetFxDevice()->CreateIoQueue( + pUnk, + TRUE, + WdfIoQueueDispatchParallel, + TRUE, + FALSE, + &fxQueue + ); + } + + if (FAILED(hr)) + { + TraceErrorHR(hr, "Failed to initialize driver queue"); + } + + if (SUCCEEDED(hr)) + { + hr = m_SocketListener.Bind(); + if (FAILED(hr)) + { + TraceErrorHR(hr, "Failed to Bind"); + } + } + + if (SUCCEEDED(hr)) + { + hr = m_SocketListener.EnableAccepting(this); + if (FAILED(hr)) + { + TraceErrorHR(hr, "Failed to EnableAccepting"); + } + } + + if (SUCCEEDED(hr)) + { + m_FxQueue = fxQueue; + } + + MethodReturnHR(hr); +} + +HRESULT +CMyQueue::Configure( + VOID + ) +/*++ + +Routine Description: + + Queue configuration function . + It is called after queue object has been succesfully initialized. + +Aruments: + + NONE + + Return Value: + + S_OK if succeeds. + +--*/ +{ + MethodEntry("void"); + + HRESULT hr = S_OK; + + MethodReturnHR(hr); +} + + +STDMETHODIMP_(void) +CMyQueue::OnCreateFile( + _In_ IWDFIoQueue* /*pWdfQueue*/, + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFFile* pWdfFile + ) + +/*++ + +Routine Description: + + Create callback from the framework for this default parallel queue + + The create request will create a socket connection , create a file i/o target associated + with the socket handle for this connection and store in the file object context. + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + pWdfFile - WDF file object for this create + + Return Value: + + VOID + +--*/ +{ + MethodEntry("pWdfRequest = %p, pWdfFile = %p", + pWdfRequest, pWdfFile); + + HRESULT hr = S_OK; + + // + // Create file context for this file object + // + + CFileContext *pContext = new CFileContext(); + if (NULL == pContext) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + TraceErrorHR(hr, "Could not create file context"); + } + + if (SUCCEEDED(hr)) + { + DWORD cchFileName = 0; + hr = pWdfFile->RetrieveFileName(NULL, &cchFileName); + if (SUCCEEDED(hr) && (cchFileName > 0) && (cchFileName <= MaxCchType)) + { + // Allocate a buffer big enough for the filename plus some extra to prevent + // overruns in the parsing below: The extra needs to be larger than the biggest + // *_CHARS value. The value 20 is overly big, but allows room to grow without + // hitting the OACR issue again. If the OACR issue is hit, just increase this + // to be larger than the biggest *_CHARS value used below in parsing. + DWORD cchFileNameBuffer = cchFileName + 20; + PWSTR pszFileNameBuffer = new WCHAR[cchFileNameBuffer]; + hr = (pszFileNameBuffer != NULL) ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + ZeroMemory(pszFileNameBuffer, cchFileNameBuffer * sizeof(WCHAR)); + + hr = pWdfFile->RetrieveFileName(pszFileNameBuffer, &cchFileName); + } + + if (SUCCEEDED(hr)) + { + PCWSTR pszFileName = pszFileNameBuffer; + if (pszFileNameBuffer[0] == L'\\') + { + // If it exists, remove the inital slash + pszFileName++; + cchFileName--; + } + + TraceInfo("cchFileName = %d, pszFileName = %S", cchFileName, pszFileName); + + PCWSTR pszProtocol = NULL; + if (CompareStringOrdinal(pszFileName, PUBS_NAMESPACE_CHARS, + PUBS_NAMESPACE, PUBS_NAMESPACE_CHARS, + TRUE) == CSTR_EQUAL) + { + pContext->SetRolePublication(); + pszProtocol = pszFileName + PUBS_NAMESPACE_CHARS; + } + else if (CompareStringOrdinal(pszFileName, SUBS_NAMESPACE_CHARS, + SUBS_NAMESPACE, SUBS_NAMESPACE_CHARS, + TRUE) == CSTR_EQUAL) + { + pContext->SetRoleSubcription(); + pszProtocol = pszFileName + SUBS_NAMESPACE_CHARS; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + if (SUCCEEDED(hr)) + { + if (CompareStringOrdinal(pszProtocol, WINDOWS_PROTOCOL_CHARS, + WINDOWS_PROTOCOL, WINDOWS_PROTOCOL_CHARS, + TRUE) == CSTR_EQUAL) + { + pContext->SetType(pszProtocol); + } + else if (CompareStringOrdinal(pszProtocol, -1, + WINDOWSURI_PROTOCOL, -1, + TRUE) == CSTR_EQUAL) + { + pContext->SetType(pszProtocol); + } + else if (CompareStringOrdinal(pszProtocol, WINDOWSMIME_PROTOCOL_CHARS, + WINDOWSMIME_PROTOCOL, WINDOWSMIME_PROTOCOL_CHARS, + TRUE) == CSTR_EQUAL) + { + pContext->SetType(pszProtocol); + } + else if (CompareStringOrdinal(pszProtocol, -1, DEVICE_ARRIVED, -1, + TRUE) == CSTR_EQUAL) + { + if (!pContext->SetRoleArrivedSubcription()) + { + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + } + else if (CompareStringOrdinal(pszProtocol, -1, DEVICE_DEPARTED, -1, + TRUE) == CSTR_EQUAL) + { + if (!pContext->SetRoleDepartedSubcription()) + { + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + } + else if (CompareStringOrdinal(pszProtocol, PAIRING_PROTOCOL_CHARS, + PAIRING_PROTOCOL, PAIRING_PROTOCOL_CHARS, + TRUE) == CSTR_EQUAL) + { + pContext->SetType(pszProtocol); + } + else if (CompareStringOrdinal(pszProtocol, NDEF_PROTOCOL_CHARS, + NDEF_PROTOCOL, NDEF_PROTOCOL_CHARS, + TRUE) == CSTR_EQUAL) + { + PCWSTR pszType = pszProtocol + NDEF_PROTOCOL_CHARS; + + if (CompareStringOrdinal(pszType, NDEF_EMPTY_TYPE_CHARS, + NDEF_EMPTY_TYPE, NDEF_EMPTY_TYPE_CHARS, + TRUE) != CSTR_EQUAL) + { + pContext->SetType(pszProtocol); + } + else + { + hr = HRESULT_FROM_NT(STATUS_INVALID_PARAMETER); + } + } + else + { + hr = HRESULT_FROM_NT(STATUS_OBJECT_PATH_NOT_FOUND); + } + } + } + + if (pszFileNameBuffer != NULL) + { + delete [] pszFileNameBuffer; + } + } + } + + if (SUCCEEDED(hr)) + { + hr = pWdfFile->AssignContext(NULL, (void*)pContext); + if (FAILED(hr)) + { + TraceErrorHR(hr, "Unable to Assign Context to this File Object"); + } + } + + if (SUCCEEDED(hr)) + { + EnterCriticalSection(&m_SubsLock); + + if (pContext->IsNormalSubscription()) + { + // Place this CFileContext into a list of Subscriptions + InsertHeadList(&m_SubsHead, pContext->GetListEntry()); + } + else if (pContext->IsArrivedSubscription()) + { + // Place this CFileContext into a list of arrival registrations + InsertHeadList(&m_ArrivalSubsHead, pContext->GetListEntry()); + } + else if (pContext->IsDepartedSubscription()) + { + // Place this CFileContext into a list of removal registrations + InsertHeadList(&m_DepartureSubsHead, pContext->GetListEntry()); + } + + LeaveCriticalSection(&m_SubsLock); + } + + if (FAILED(hr)) + { + if (pContext != NULL) + { + delete pContext; + pContext = NULL; + } + } + + pWdfRequest->Complete(hr); + + MethodReturnVoid(); +} + +STDMETHODIMP_(void) +CMyQueue::OnCloseFile( + _In_ IWDFFile* pWdfFileObject + ) +/*++ + + Routine Description: + + This method is called when an app closes the file handle to this device. + This will free the context memory associated with this file object, close + the connection object associated with this file object and delete the file + handle i/o target object associated with this file object. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + MethodEntry("..."); + + HRESULT hr = S_OK ; + CFileContext* pContext = NULL; + hr = pWdfFileObject->RetrieveContext((void**)&pContext); + if (SUCCEEDED(hr) && (pContext != NULL)) + { + CRITICAL_SECTION* pCritSec = NULL; + LIST_ENTRY* pHead = NULL; + + if (pContext->IsNormalSubscription()) + { + pCritSec = &m_SubsLock; + pHead = &m_SubsHead; + } + else if (pContext->IsArrivedSubscription()) + { + pCritSec = &m_SubsLock; + pHead = &m_ArrivalSubsHead; + } + else if (pContext->IsDepartedSubscription()) + { + pCritSec = &m_SubsLock; + pHead = &m_DepartureSubsHead; + } + else if (pContext->IsPublication()) + { + pCritSec = &m_PubsLock; + pHead = &m_PubsHead; + } + + if (pHead != NULL) + { + EnterCriticalSection(pCritSec); + + LIST_ENTRY* pFindEntry = pContext->GetListEntry(); + LIST_ENTRY* pEntry = pHead->Flink; + while (pEntry != pHead) + { + if (pEntry == pFindEntry) + { + RemoveEntryList(pEntry); + break; + } + + pEntry = pEntry->Flink; + } + + LeaveCriticalSection(pCritSec); + } + + delete pContext; + } + + MethodReturnVoid(); +} + +STDMETHODIMP_ (void) +CMyQueue::OnCancel( + _In_ IWDFIoRequest* pWdfRequest + ) +{ + MethodEntry("pWdfRequest = %p", + pWdfRequest); + + IWDFFile* pFxFile; + pWdfRequest->GetFileObject(&pFxFile); + if (pFxFile != NULL) + { + CFileContext* pFileContext; + HRESULT hr = pFxFile->RetrieveContext((void**)&pFileContext); + if (SUCCEEDED(hr)) + { + pFileContext->OnCancel(); + } + } + + MethodReturnVoid(); +} + +#define IOCTL_BEGIN_PROXIMITY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS) + +STDMETHODIMP_ (void) +CMyQueue::OnDeviceIoControl( + _In_ IWDFIoQueue* /*pWdfQueue*/, + _In_ IWDFIoRequest* pWdfRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T /*InBufferSize*/, + _In_ SIZE_T /*OutBufferSize*/ + ) +{ + MethodEntry("pWdfRequest = %p, ControlCode = %d", + pWdfRequest, ControlCode); + + IWDFFile* pFxFile; + + pWdfRequest->GetFileObject(&pFxFile); + + bool fCompleteRequest = true; + + CFileContext *pFileContext; + HRESULT hr = pFxFile->RetrieveContext((void**)&pFileContext); + if (SUCCEEDED(hr)) + { + switch (ControlCode) + { + case IOCTL_NFP_GET_MAX_MESSAGE_BYTES: + { + IWDFMemory* pWdfOutputMemory; + pWdfRequest->GetOutputMemory(&pWdfOutputMemory); + if (pWdfOutputMemory != NULL) + { + SIZE_T cbOutputBuffer = 0; + // Set the first 4 bytes as the maximum message size of this device/driver + DWORD dwMaxCbPayload = MaxCbPayload; + hr = pWdfOutputMemory->CopyFromBuffer(0, &dwMaxCbPayload, 4); + if (SUCCEEDED(hr)) + { + cbOutputBuffer = 4; + } + pWdfOutputMemory->Release(); + + pWdfRequest->CompleteWithInformation(hr, cbOutputBuffer); + fCompleteRequest = false; + } + } + break; + + case IOCTL_NFP_GET_KILO_BYTES_PER_SECOND: + { + IWDFMemory* pWdfOutputMemory; + pWdfRequest->GetOutputMemory(&pWdfOutputMemory); + if (pWdfOutputMemory != NULL) + { + SIZE_T cbOutputBuffer = 0; + // Set the first 4 bytes as transfer speed of this device/driver + DWORD dwKilobytesPerSecond = KilobytesPerSecond; + hr = pWdfOutputMemory->CopyFromBuffer(0, &dwKilobytesPerSecond, 4); + if (SUCCEEDED(hr)) + { + cbOutputBuffer = 4; + } + pWdfOutputMemory->Release(); + + pWdfRequest->CompleteWithInformation(hr, cbOutputBuffer); + fCompleteRequest = false; + } + } + break; + + case IOCTL_NFP_DISABLE: + hr = pFileContext->Disable(); + break; + + case IOCTL_NFP_ENABLE: + hr = pFileContext->Enable(); + break; + + case IOCTL_NFP_SET_PAYLOAD: + hr = pFileContext->SetPayload(pWdfRequest); + if (SUCCEEDED(hr)) + { + MESSAGE* pMessage = new MESSAGE(); + hr = (pMessage != NULL) ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + pMessage->Initialize(pFileContext->GetType(), pFileContext->GetSize(), pFileContext->GetPayload()); + + EnterCriticalSection(&m_ConnectionLock); + + for (LIST_ENTRY* pEntry = m_ConnectionHead.Flink; + pEntry != &m_ConnectionHead; + pEntry = pEntry->Flink) + { + CConnection* pConnection = CConnection::FromListEntry(pEntry); + if (SUCCEEDED(pConnection->TransmitMessage(pMessage))) + { + pFileContext->HandleMessageTransmitted(); + } + } + + LeaveCriticalSection(&m_ConnectionLock); + + // Place this CFileContext into a list of published messages + EnterCriticalSection(&m_PubsLock); + InsertHeadList(&m_PubsHead, pFileContext->GetListEntry()); + LeaveCriticalSection(&m_PubsLock); + + delete pMessage; + } + } + break; + + case IOCTL_BEGIN_PROXIMITY: + hr = pFileContext->BeginProximity(pWdfRequest, this); + break; + + case IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE: + hr = pFileContext->GetNextSubscribedMessage(this, pWdfRequest); + if (SUCCEEDED(hr)) + { + fCompleteRequest = false; + } + break; + + case IOCTL_NFP_GET_NEXT_TRANSMITTED_MESSAGE: + hr = pFileContext->GetNextTransmittedMessage(this, pWdfRequest); + if (SUCCEEDED(hr)) + { + fCompleteRequest = false; + } + break; + + default: + hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE); + break; + } + } + + if (fCompleteRequest) + { + TraceInfo("Completing Request: %!HRESULT!", hr); + pWdfRequest->Complete(hr); + } + + MethodReturnVoid(); +} + +void +CMyQueue::ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket) +{ + MethodEntry("..."); + + CConnection* pConnection; + HRESULT hr = CConnection::Create(this, &pConnection); + if (SUCCEEDED(hr)) + { + // Mark it as an Inbound connection, so we know to delete it when + // it's removed from the list + pConnection->SetInboundConnection(); + + pConnection->ValidateAccept(Socket, pMagicPacket); + Socket = INVALID_SOCKET; + } + + if (Socket != INVALID_SOCKET) + { + closesocket(Socket); + } + + MethodReturnVoid(); +} + +void +CMyQueue::HandleReceivedMessage(_In_ MESSAGE* pMessage) +{ + MethodEntry("pMessage->m_szType = '%S'", + pMessage->m_szType); + + if ((pMessage->m_cbPayload > 0) && (pMessage->m_cbPayload <= MaxCbPayload)) + { + EnterCriticalSection(&m_SubsLock); + + LIST_ENTRY* pEntry = m_SubsHead.Flink; + while (pEntry != &m_SubsHead) + { + CFileContext* pSub = CFileContext::FromListEntry(pEntry); + + pSub->HandleReceivedPublication(pMessage->m_szType, + pMessage->m_cbPayload, + pMessage->m_Payload); + + pEntry = pEntry->Flink; + } + + LeaveCriticalSection(&m_SubsLock); + } + + MethodReturnVoid(); +} + +void +CMyQueue::ConnectionEstablished(_In_ CConnection* pConnection) +{ + MethodEntry("..."); + + EnterCriticalSection(&m_ConnectionLock); + BOOL fFirstConnection = IsListEmpty(&m_ConnectionHead); + InsertHeadList(&m_ConnectionHead, pConnection->GetListEntry()); + LeaveCriticalSection(&m_ConnectionLock); + + if (fFirstConnection) + { + AddArrivalEvent(); + } + + MESSAGE* pMessage = new MESSAGE(); + if (pMessage != NULL) + { + EnterCriticalSection(&m_PubsLock); + + LIST_ENTRY* pEntry = m_PubsHead.Flink; + while (pEntry != &m_PubsHead) + { + CFileContext* pPub = CFileContext::FromListEntry(pEntry); + if (pPub->IsEnabled()) + { + pMessage->Initialize(pPub->GetType(), pPub->GetSize(), pPub->GetPayload()); + if (SUCCEEDED(pConnection->TransmitMessage(pMessage))) + { + pPub->HandleMessageTransmitted(); + } + } + pEntry = pEntry->Flink; + } + + LeaveCriticalSection(&m_PubsLock); + delete pMessage; + } + + MethodReturnVoid(); +} + +BOOL +CMyQueue::ConnectionTerminated(_In_ CConnection* pConnection) +{ + MethodEntry("pConnection = 0x%p", + pConnection); + + LIST_ENTRY* pRemoveListEntry = pConnection->GetListEntry(); + + EnterCriticalSection(&m_ConnectionLock); + LIST_ENTRY* pEntry = m_ConnectionHead.Flink; + while (pEntry != &m_ConnectionHead) + { + if (pEntry == pRemoveListEntry) + { + RemoveEntryList(pEntry); + break; + } + pEntry = pEntry->Flink; + } + BOOL fNoMoreConnections = IsListEmpty(&m_ConnectionHead); + + LeaveCriticalSection(&m_ConnectionLock); + + BOOL fConnectionDeleted = FALSE; + if (pConnection->IsInboundConnection()) + { + delete pConnection; + fConnectionDeleted = TRUE; + } + + if (fNoMoreConnections) + { + AddRemovalEvent(); + } + + MethodReturnBool(fConnectionDeleted); +} + +void +CMyQueue::AddArrivalEvent() +{ + MethodEntry("void"); + + EnterCriticalSection(&m_SubsLock); + + for (LIST_ENTRY* pEntry = m_ArrivalSubsHead.Flink; + pEntry != &m_ArrivalSubsHead; + pEntry = pEntry->Flink) + { + CFileContext::FromListEntry(pEntry)->HandleArrivalEvent(); + } + + LeaveCriticalSection(&m_SubsLock); + + MethodReturnVoid(); +} + +void +CMyQueue::AddRemovalEvent() +{ + MethodEntry("void"); + + EnterCriticalSection(&m_SubsLock); + + for (LIST_ENTRY* pEntry = m_DepartureSubsHead.Flink; + pEntry != &m_DepartureSubsHead; + pEntry = pEntry->Flink) + { + CFileContext::FromListEntry(pEntry)->HandleRemovalEvent(); + } + + LeaveCriticalSection(&m_SubsLock); + + MethodReturnVoid(); +} + +STDMETHODIMP_(void) +CMyQueue::OnCleanup( + _In_ IWDFObject* /*pWdfObject*/ + ) +{ + MethodEntry("..."); + + // + // CMyQueue has a reference to framework device object via m_Queue. + // Framework queue object has a reference to CMyQueue object via the callbacks. + // This leads to circular reference and both the objects can't be destroyed until this circular reference is broken. + // To break the circular reference we release the reference to the framework queue object here in OnCleanup. + // + + m_FxQueue = NULL; + + MethodReturnVoid(); +} diff --git a/nfp/net/driver/Queue.h b/nfp/net/driver/Queue.h new file mode 100644 index 00000000..55b2ff39 --- /dev/null +++ b/nfp/net/driver/Queue.h @@ -0,0 +1,175 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + user mode only + +Revision History: + +--*/ + +#pragma once + +#include "device.h" +#include "Connection.h" + +static const int KilobytesPerSecond = 20; + +static const int MaxCbPayload = 10240; +static const int MaxCchType = 507; // maximum message type length is 5 for "?ubs\\", 250 for protocol + 250 for subtype + 1 each for dot "." and NULL terminator. +static const int MaxCchTypeNetwork = 502; // maximum message type length over the network is 250 for protocol + 250 for subtype + 1 each for dot "." and NULL terminator. +static const int MinCchType = 2; +static const int MaxCchMimeType = 256; + +#define WINDOWS_PROTOCOL L"Windows." +#define WINDOWS_PROTOCOL_CHARS 8 + +#define WINDOWSURI_PROTOCOL L"WindowsUri" + +#define WINDOWSMIME_PROTOCOL L"WindowsMime" +#define WINDOWSMIME_PROTOCOL_CHARS 11 + +#define PUBS_NAMESPACE L"Pubs\\" +#define PUBS_NAMESPACE_CHARS 5 + +#define SUBS_NAMESPACE L"Subs\\" +#define SUBS_NAMESPACE_CHARS 5 + +#define DEVICE_ARRIVED L"DeviceArrived" +#define DEVICE_DEPARTED L"DeviceDeparted" + +#define PAIRING_PROTOCOL L"Pairing:" +#define PAIRING_PROTOCOL_CHARS 8 + +#define NDEF_PROTOCOL L"NDEF" +#define NDEF_PROTOCOL_CHARS 4 + +#define NDEF_EMPTY_TYPE L"Empty" +#define NDEF_EMPTY_TYPE_CHARS 5 + +struct MESSAGE +{ + MESSAGE() : + m_cbPayload(0) + { + ZeroMemory(m_szType, sizeof(m_szType)); + ZeroMemory(m_Payload, sizeof(m_Payload)); + } + + void Initialize( + _In_ PCWSTR szType, + _In_ DWORD cbPayload, + _In_reads_bytes_(cbPayload) PBYTE pbPayload + ) + { + ZeroMemory(m_szType, sizeof(m_szType)); + ZeroMemory(m_Payload, sizeof(m_Payload)); + + m_cbPayload = cbPayload; + StringCchCopy(m_szType, ARRAY_SIZE(m_szType), szType); + CopyMemory(m_Payload, pbPayload, cbPayload); + } + + wchar_t m_szType[MaxCchTypeNetwork]; + DWORD m_cbPayload; + BYTE m_Payload[MaxCbPayload]; +}; + + +// +// Queue Callback Object. +// + +class ATL_NO_VTABLE CMyQueue : + public CComObjectRootEx<CComMultiThreadModel>, + public IQueueCallbackCreate, + public IQueueCallbackDeviceIoControl, + public IRequestCallbackCancel, + public IObjectCleanup, + public IValidateAccept, + public IConnectionCallback +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyQueue) + +BEGIN_COM_MAP(CMyQueue) + COM_INTERFACE_ENTRY(IQueueCallbackCreate) + COM_INTERFACE_ENTRY(IQueueCallbackDeviceIoControl) + COM_INTERFACE_ENTRY(IRequestCallbackCancel) + COM_INTERFACE_ENTRY(IObjectCleanup) +END_COM_MAP() + +public: + + //IQueueCallbackCreate + STDMETHOD_(void,OnCreateFile)(_In_ IWDFIoQueue* pWdfQueue, _In_ IWDFIoRequest* pWDFRequest, _In_ IWDFFile* pWdfFileObject); + + //IQueueCallbackDeviceIoControl + STDMETHOD_(void,OnDeviceIoControl)(_In_ IWDFIoQueue* pWdfQueue, _In_ IWDFIoRequest* pWDFRequest, _In_ ULONG ControlCode, _In_ SIZE_T InBufferSize, _In_ SIZE_T OutBufferSize); + + //IObjectCleanup + STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject); + + //IValidateAccept + void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket); + + + //IRequestCallbackCancel + STDMETHODIMP_(void) + OnCancel( + _In_ IWDFIoRequest* pWdfRequest + ); + + //IConnectionCallback + virtual void HandleReceivedMessage(_In_ MESSAGE* pMessageData); + virtual void ConnectionEstablished(_In_ CConnection* pBthConnection); + virtual BOOL ConnectionTerminated(_In_ CConnection* pBthConnection); + +public: + CMyQueue(); + ~CMyQueue(); + + STDMETHOD(Initialize)(_In_ CMyDevice * Device); + + HRESULT + Configure( + VOID + ); + + STDMETHODIMP_(void) + OnCloseFile( + _In_ IWDFFile* pWdfFileObject + ); + +private: + + void AddArrivalEvent(); + void AddRemovalEvent(); + +private: + CComPtr<IWDFIoQueue> m_FxQueue; + + LIST_ENTRY m_SubsHead; + LIST_ENTRY m_ArrivalSubsHead; + LIST_ENTRY m_DepartureSubsHead; + CRITICAL_SECTION m_SubsLock; + + LIST_ENTRY m_PubsHead; + CRITICAL_SECTION m_PubsLock; + + LIST_ENTRY m_ConnectionHead; + CRITICAL_SECTION m_ConnectionLock; + + CSocketListener m_SocketListener; +}; diff --git a/nfp/net/driver/connection.h b/nfp/net/driver/connection.h new file mode 100644 index 00000000..6ab900e0 --- /dev/null +++ b/nfp/net/driver/connection.h @@ -0,0 +1,125 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Abstract: + + Defines a simple NearFieldProximity Provider implementation using the network + for use in selfhosting. + +Author: + + Travis Martin (TravM) 06-24-2010 + +--*/ +#pragma once + +#include "SocketListener.h" + +class CConnection; + +struct MESSAGE; + +interface IConnectionCallback +{ + virtual void HandleReceivedMessage(_In_ MESSAGE* pMessage) = 0; + virtual void ConnectionEstablished(_In_ CConnection* pConnection) = 0; + virtual BOOL ConnectionTerminated(_In_ CConnection* pConnection) = 0; +}; + +class CConnection : public IValidateAccept +{ +private: + CConnection(_In_ IConnectionCallback* pCallback) : + _State(INITIAL), + _Socket(INVALID_SOCKET), + _pCallback(pCallback), + _ThreadpoolWork(NULL), + _fInboundConnection(false) + { + } + +public: + + virtual ~CConnection() + { + Terminate(); + + if (_ThreadpoolWork != NULL) + { + // Don't wait for threadpool callbacks when this thread is actually the threadpool callback + if (_ThreadpoolThreadId != GetCurrentThreadId()) + { + WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false); + } + CloseThreadpoolWork(_ThreadpoolWork); + _ThreadpoolWork = NULL; + } + } + + static HRESULT Create(_In_ IConnectionCallback* pCallback, _Outptr_ CConnection** ppConnection); + + void SetInboundConnection() { _fInboundConnection = true; } + bool IsInboundConnection() { return _fInboundConnection; } + + //IValidateAccept + void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket); + + HRESULT FinalizeEstablish(_In_ SOCKET Socket); + + HRESULT InitializeAsClient(_In_ BEGIN_PROXIMITY_ARGS* pArgs); + + HRESULT TransmitMessage(_In_ MESSAGE* pMessage); + + BOOL ReceiveThreadProc(); + static VOID CALLBACK s_ReceiveThreadProc( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_ PVOID Context, + _Inout_ PTP_WORK /*Work*/) + { + CallbackMayRunLong(Instance); + + CConnection* pConnection = (CConnection*)Context; + pConnection->_ThreadpoolThreadId = GetCurrentThreadId(); + BOOL fConnectionDeleted = pConnection->ReceiveThreadProc(); + + if (!fConnectionDeleted) + { + // Only clear the member variable if the connection object wasn't deleted. + pConnection->_ThreadpoolThreadId = 0; + } + } + + LIST_ENTRY* GetListEntry() { return &_ListEntry; } + static CConnection* FromListEntry(LIST_ENTRY* pListEntry) + { + return (CConnection*) CONTAINING_RECORD(pListEntry, CConnection, _ListEntry); + } + +private: + + void Terminate(); + +private: + + enum STATE + { + INITIAL = 0, + ESTABLISHED, + TERMINATED + }; + + volatile STATE _State; + + SOCKET _Socket; + + PTP_WORK _ThreadpoolWork; + DWORD _ThreadpoolThreadId; + + IConnectionCallback* _pCallback; + + bool _fInboundConnection; + + LIST_ENTRY _ListEntry; + +}; diff --git a/nfp/net/driver/device.cpp b/nfp/net/driver/device.cpp new file mode 100644 index 00000000..599d57b5 --- /dev/null +++ b/nfp/net/driver/device.cpp @@ -0,0 +1,261 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the UMDF sample + driver's device callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "device.tmh" + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver* FxDriver, + _In_ IWDFDeviceInitialize* FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + FxDriver - IWDF Driver for this device. + + Return Value: + + status. + +--*/ +{ + MethodEntry("..."); + + CComPtr<IWDFDevice> fxDevice; + HRESULT hr; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // Set the locking model + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + + CComPtr<IUnknown> pUnk; + HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk); + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + hr = FxDriver->CreateDevice(FxDeviceInit, pUnk, &fxDevice); + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + } + + MethodReturnHR(hr); +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + MethodEntry("void"); + + // + // Create a new instance of our Queue callback object + // + CComObject<CMyQueue> * defaultQueue = NULL; + HRESULT hr = CComObject<CMyQueue>::CreateInstance(&defaultQueue); + + if (SUCCEEDED(hr)) + { + defaultQueue->AddRef(); + hr = defaultQueue->Initialize(this); + } + + if (SUCCEEDED(hr)) + { + hr = defaultQueue->Configure(); + } + + // + // Create and Enable Device Interfaces for this device. + // + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_NETNFP, + NULL); + } + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_NETNFP, + NULL, + TRUE); + } + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_NFP, + NULL); + } + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_NFP, + NULL, + TRUE); + } + + if (SUCCEEDED(hr)) + { + // + // Save a pointer to our queue, so we can lock it during file cleanup + // + m_MyQueue = defaultQueue; + } + + // + // Release the reference we took on the queue object. + // The framework took its own references on the object's callback interfaces + // when we called m_FxDevice->CreateIoQueue, and will manage the object's lifetime. + // + SAFE_RELEASE(defaultQueue); + + MethodReturnHR(hr); +} + +STDMETHODIMP_(void) +CMyDevice::OnCloseFile( + _In_ IWDFFile* pWdfFileObject + ) +{ + MethodEntry("..."); + + m_MyQueue->OnCloseFile(pWdfFileObject); + + MethodReturnVoid(); +} + +STDMETHODIMP_(void) +CMyDevice::OnCleanupFile( + _In_ IWDFFile* /*pWdfFileObject*/ + ) +/*++ + + Routine Description: + + This method is when app with open handle device terminates. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ +} + +STDMETHODIMP_(void) +CMyDevice::OnCleanup( + _In_ IWDFObject* pWdfObject + ) +/*++ + + Routine Description: + + This device callback method is invoked by the framework when the WdfObject + is about to be released by the framework. + + Arguments: + + pWdfObject - the framework device object for which OnCleanup. + + Return Value: + + None + +--*/ +{ + MethodEntry("..."); + + WUDF_SAMPLE_DRIVER_ASSERT(pWdfObject == m_FxDevice); + + m_MyQueue = NULL; + + // + // CMyDevice has a reference to framework device object via m_Device. + // Framework device object has a reference to CMyDevice object via the callbacks. + // This leads to circular reference and both the objects can't be destroyed until this circular reference is broken. + // To break the circular reference we release the reference to the framework device object here in OnCleanup. + // + m_FxDevice = NULL; + + MethodReturnVoid(); +} diff --git a/nfp/net/driver/device.h b/nfp/net/driver/device.h new file mode 100644 index 00000000..c4eeb121 --- /dev/null +++ b/nfp/net/driver/device.h @@ -0,0 +1,73 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ +#pragma once + +class CMyQueue; + +class ATL_NO_VTABLE CMyDevice : + public CComObjectRootEx<CComMultiThreadModel>, + public IFileCallbackCleanup, + public IFileCallbackClose, + public IObjectCleanup +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyDevice) + +BEGIN_COM_MAP(CMyDevice) + COM_INTERFACE_ENTRY(IFileCallbackCleanup) + COM_INTERFACE_ENTRY(IFileCallbackClose) + COM_INTERFACE_ENTRY(IObjectCleanup) +END_COM_MAP() + +public: + + //IFileCallbackCleanup + STDMETHOD_(void,OnCleanupFile)(_In_ IWDFFile* pWdfFileObject); + //IFileCallbackClose + STDMETHOD_(void,OnCloseFile)(_In_ IWDFFile* pWdfFileObject); + //IObjectCleanup + STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject); + +public: + + STDMETHOD(Initialize)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit); + + HRESULT + Configure( + VOID + ); + + IWDFDevice * + GetFxDevice( + VOID + ) + { + return m_FxDevice; + } + +private: + CComPtr<IWDFDevice> m_FxDevice; + + CMyQueue* m_MyQueue; + + HRESULT ReadAndAssignPropertyStoreValue(); + HRESULT GetAnsiValFromPropVariant(_In_ PROPVARIANT val, _Inout_ LPSTR *PropertyValueA); + +}; diff --git a/nfp/net/driver/dllsup.cpp b/nfp/net/driver/dllsup.cpp new file mode 100644 index 00000000..85c866ec --- /dev/null +++ b/nfp/net/driver/dllsup.cpp @@ -0,0 +1,112 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF Socktecho Sample + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +class CNetNfpProviderModule : public CAtlDllModuleT< CNetNfpProviderModule > +{ +}; + + +OBJECT_ENTRY_AUTO(CLSID_MyDriverCoClass, CMyDriver) + + +CNetNfpProviderModule _AtlModule; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID Reserved + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + UNREFERENCED_PARAMETER( ModuleHandle ); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + TracingTlsInitialize(); + + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + TracingTlsFree(); + WPP_CLEANUP(); + } + + return _AtlModule.DllMain(Reason, Reserved); +; +} + +_Check_return_ +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) +{ + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} diff --git a/nfp/net/driver/driver.cpp b/nfp/net/driver/driver.cpp new file mode 100644 index 00000000..2c28f16e --- /dev/null +++ b/nfp/net/driver/driver.cpp @@ -0,0 +1,150 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF Socketecho Sample's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ +#include "internal.h" + +#include "driver.tmh" + +DECLARE_TRACING_TLS; + +STDMETHODIMP +CMyDriver::OnInitialize( + _In_ IWDFDriver* /*pWdfDriver*/ + ) + + +/*++ + + Routine Description: + + This routine is invoked by the framework at driver load . + This method will invoke the Winsock Library for using + Winsock API in this driver. + + Arguments: + + pWdfDriver - Framework driver object + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ + +{ + MethodEntry("..."); + + HRESULT hr = S_OK; + + WSADATA wsaData; + int result = WSAStartup(MAKEWORD(2,2), &wsaData); + if (result != 0) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + TraceErrorHR(hr, "Failed to initialize Winsock 2.0"); + } + + MethodReturnHR(hr); +} + +STDMETHODIMP_(void) +CMyDriver::OnDeinitialize( + _In_ IWDFDriver* /*pWdfDriver*/ + ) + +/*++ + Routine Description: + + The FX invokes this method when it unloads the driver. + This routine will Cleanup Winsock library + + Arguments: + + pWdfDriver - the Fx driver object. + + Return Value: + + None + + --*/ +{ + MethodEntry("..."); + + WSACleanup(); + + MethodReturnVoid(); +} + +STDMETHODIMP +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + MethodEntry("..."); + + // + // Create a new instance of our device callback object + // + + CComObject<CMyDevice> * device; + HRESULT hr = CComObject<CMyDevice>::CreateInstance(&device); + if (SUCCEEDED(hr)) + { + device->AddRef(); + hr = device->Initialize(FxWdfDriver, FxDeviceInit); + if (SUCCEEDED(hr)) + { + // + // If that succeeded then call the device's configure method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + hr = device->Configure(); + } + + // + // Release the reference we took on the device object. + // The framework took its own references on the object's callback interfaces + // when we called FxWdfDriver->CreateDevice, and will manage the object's lifetime. + // + SAFE_RELEASE(device); + } + + MethodReturnHR(hr); +} diff --git a/nfp/net/driver/driver.h b/nfp/net/driver/driver.h new file mode 100644 index 00000000..6affa20f --- /dev/null +++ b/nfp/net/driver/driver.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF Socketecho sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the socktecho sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +extern const GUID CLSID_MyDriverCoClass; + +class ATL_NO_VTABLE CMyDriver : + public CComObjectRootEx<CComMultiThreadModel>, + public CComCoClass<CMyDriver, &CLSID_MyDriverCoClass>, + public IDriverEntry +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyDriver) + +DECLARE_CLASSFACTORY(); + +DECLARE_NO_REGISTRY(); + +BEGIN_COM_MAP(CMyDriver) + COM_INTERFACE_ENTRY(IDriverEntry) +END_COM_MAP() + +public: + // IDriverEntry + STDMETHOD(OnInitialize)(_In_ IWDFDriver* pWdfDriver); + STDMETHOD(OnDeviceAdd)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit); + STDMETHOD_(void,OnDeinitialize)(_In_ IWDFDriver* pWdfDriver); +}; + diff --git a/nfp/net/driver/exports.def b/nfp/net/driver/exports.def new file mode 100644 index 00000000..964e5f79 --- /dev/null +++ b/nfp/net/driver/exports.def @@ -0,0 +1,6 @@ +; exports.def : Declares the module parameters. + +LIBRARY "NetNfpProvider" + +EXPORTS + DllGetClassObject PRIVATE diff --git a/nfp/net/driver/internal.h b/nfp/net/driver/internal.h new file mode 100644 index 00000000..80aa0152 --- /dev/null +++ b/nfp/net/driver/internal.h @@ -0,0 +1,152 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF Socketecho sample + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the winsock headers before any other windows headers. +// +#include <winsock2.h> +#include <ws2tcpip.h> + +// +// Include the WUDF DDI +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Define the tracing GUID for this driver +// + +#define TRACE_CONTROL_GUID (12579E92,1B46,40A6,9CFC,C718A677830B) + + +// +// Driver specific #defines +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\NetNfpProvider" + +/* 278F44F0-FF5C-4FE3-BF20-F8AA158EA7BC */ +#define MYDRIVER_CLASS_ID { 0x278F44F0, 0xFF5C, 0x4FE3, {0xBF, 0x20, 0xF8, 0xAA, 0x15, 0x8E, 0xA7, 0xBC} } +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} +#endif + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_SAMPLE_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +// +// define the maximum size of the message queue +// + +#define MAX_MESSAGE_QUEUE_SIZE 50 + +// +// MessageId: STATUS_CANCELLED +// +// MessageText: +// +// The I/O request was canceled. +// +#define STATUS_CANCELLED (0xC0000120L) + +// +// MessageId: STATUS_INVALID_DEVICE_STATE +// +// MessageText: +// +// The device is not in a valid state to perform this request. +// +#define STATUS_INVALID_DEVICE_STATE (0xC0000184L) + +// +// MessageId: STATUS_INVALID_BUFFER_SIZE +// +// MessageText: +// +// The size of the buffer is invalid for the specified operation. +// +#define STATUS_INVALID_BUFFER_SIZE (0xC0000206L) + +// +// MessageId: STATUS_OBJECT_PATH_NOT_FOUND +// +// MessageText: +// +// {Path Not Found} +// The path %hs does not exist. +// +#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS)0xC000003AL) + +// +// Include the type specific headers. +// +#include <atlbase.h> +#include <atlcom.h> + +// Windows Headers +#include <initguid.h> +#include <Winsock2.h> +#include <Mswsock.h> +#include <Strsafe.h> +#include <devioctl.h> +#include <nfpdev.h> + +// Sample headers +#include "NetNfp.h" +#include "WppDefs.h" +#include "list.h" +#include "connection.h" +#include "filecontext.h" +#include "driver.h" +#include "device.h" +#include "queue.h" + +_Analysis_mode_(_Analysis_operator_new_null_) + diff --git a/nfp/net/driver/list.h b/nfp/net/driver/list.h new file mode 100644 index 00000000..d2bfce3f --- /dev/null +++ b/nfp/net/driver/list.h @@ -0,0 +1,119 @@ +#pragma once + +FORCEINLINE +VOID +InitializeListHead( + _Out_ PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +_Check_return_ +BOOLEAN +FORCEINLINE +IsListEmpty( + _In_ const LIST_ENTRY * ListHead + ) +{ + return (BOOLEAN)(ListHead->Flink == ListHead); +} + +FORCEINLINE +BOOLEAN +RemoveEntryList( + _In_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return (BOOLEAN)(Flink == Blink); +} + +FORCEINLINE +PLIST_ENTRY +RemoveHeadList( + _Inout_ PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Flink; + PLIST_ENTRY Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + return Entry; +} + + + +FORCEINLINE +PLIST_ENTRY +RemoveTailList( + _Inout_ PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Entry; + + Entry = ListHead->Blink; + Blink = Entry->Blink; + ListHead->Blink = Blink; + Blink->Flink = ListHead; + return Entry; +} + + +FORCEINLINE +VOID +InsertTailList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ __drv_aliasesMem PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} + + +FORCEINLINE +VOID +InsertHeadList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ __drv_aliasesMem PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink; + + Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +FORCEINLINE +VOID +AppendTailList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY ListToAppend + ) +{ + PLIST_ENTRY ListEnd = ListHead->Blink; + + ListHead->Blink->Flink = ListToAppend; + ListHead->Blink = ListToAppend->Blink; + ListToAppend->Blink->Flink = ListHead; + ListToAppend->Blink = ListEnd; +} diff --git a/nfp/net/driver/netnfpprovider.inx b/nfp/net/driver/netnfpprovider.inx new file mode 100644 index 00000000..0f2d246f --- /dev/null +++ b/nfp/net/driver/netnfpprovider.inx @@ -0,0 +1,83 @@ +; +; NetNfpProvider.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class=Proximity +ClassGuid={5630831C-06C9-4856-B327-F5D32586E060} +Provider=%MSFT% +CatalogFile=nfp.cat +DriverVer=03/20/2003,5.00.3788 + +[Manufacturer] +%MSFTWUDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%NetNfpProviderName%=NetNfpProvider_Install,WUDF\NetNfpProvider + +[SourceDisksFiles] +NetNfpProvider.dll=1 + + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== WUDF NetNfpProvider Test Driver ================================== + +[NetNfpProvider_Install] +CopyFiles=UMDFDriverCopy + +[NetNfpProvider_Install.hw] +AddReg=NetNfpProvider_AddReg + +[NetNfpProvider_Install.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[NetNfpProvider_Install.CoInstallers] +AddReg = NetNfpProvider_Install.CoInstallers_AddReg +CopyFiles = CoInstallers_CopyFiles + +[NetNfpProvider_Install.CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WUDFCoinstaller.dll" + + + +[CoInstallers_CopyFiles] +;WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[NetNfpProvider_Install.Wdf] +UmdfService=NetNfpProvider, NetNfpProvider_Driver_Install +UmdfServiceOrder=NetNfpProvider +UmdfDispatcher=FileHandle + +[NetNfpProvider_AddReg] +HKR,"NetNfpProvider","Server",0x00010001,1 + +[WUDFRD_ServiceInstall] +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\WUDFRd.sys + +[NetNfpProvider_Driver_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID="{278F44F0-FF5C-4FE3-BF20-F8AA158EA7BC}" +ServiceBinary="%12%\UMDF\NetNfpProvider.dll" + +[DestinationDirs] +UMDFDriverCopy=12,UMDF + +[UMDFDriverCopy] +NetNfpProvider.dll + +; =================== Generic ================================== + +[Strings] +MSFT="Microsoft" +MSFTWUDF="Microsoft Windows Driver Kit Sample (Proximity)" +MediaDescription="Microsoft Network NearFieldProximity Provider Installation Media" +NetNfpProviderName="Network NearFieldProximity Provider" + + + diff --git a/nfp/net/driver/netnfpprovider.rc b/nfp/net/driver/netnfpprovider.rc new file mode 100644 index 00000000..98d1f8ab --- /dev/null +++ b/nfp/net/driver/netnfpprovider.rc @@ -0,0 +1,18 @@ +//--------------------------------------------------------------------------- +// Skeleton.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Network NearFieldProximity Provider" +#define VER_INTERNALNAME_STR "NetNfpProvider" +#define VER_ORIGINALFILENAME_STR "NetNfpProvider.dll" + +#include "common.ver" diff --git a/nfp/net/driver/socketlistener.cpp b/nfp/net/driver/socketlistener.cpp new file mode 100644 index 00000000..3aaa687b --- /dev/null +++ b/nfp/net/driver/socketlistener.cpp @@ -0,0 +1,222 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Abstract: + + Implements a socket listener class + +Author: + + Travis Martin (TravM) 06-24-2010 + +Environment: + + User-mode only. + +--*/ +#include "internal.h" + +#include "SocketListener.tmh" + +HRESULT SetSocketIpv6Only(_In_ SOCKET socket, _In_ BOOL Ipv6Only) +{ + HRESULT hr = S_OK; + if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&Ipv6Only, sizeof(Ipv6Only)) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + USE_DEFAULT_TRACING_CONTEXT; + TraceErrorHR(hr, "setsockopt IPV6_V6ONLY"); + } + return hr; +} + +HRESULT CSocketListener::EnableAccepting(_In_ IValidateAccept* pValidator) +{ + HRESULT hr = S_OK; + if (_pValidator == NULL) + { + USE_DEFAULT_TRACING_CONTEXT; + + _ThreadpoolIo = CreateThreadpoolIo((HANDLE)_ListenSocket, s_AcceptThreadProc, this, NULL); + if (_ThreadpoolIo == NULL) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + if (SUCCEEDED(hr)) + { + int backlog = 2; + if (listen(_ListenSocket, backlog) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + } + + if (SUCCEEDED(hr)) + { + // We're now accepting + _pValidator = pValidator; + + hr = BeginAccept(); + if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING)) + { + hr = S_OK; + } + } + + TraceInfo("EnableAccepting(): %!HRESULT!", hr); + } + + return hr; +} + +void CSocketListener::StopAccepting() +{ + MethodEntry("void"); + + SOCKET listenSocket = InterlockedExchange(&_ListenSocket, INVALID_SOCKET); + if (listenSocket != INVALID_SOCKET) + { + closesocket(listenSocket); + } + + PTP_IO threadpoolIo = (PTP_IO)InterlockedExchangePointer((PVOID*)&_ThreadpoolIo, NULL); + if (threadpoolIo != NULL) + { + // Don't wait for threadpool callbacks when this thread is actually the threadpool callback + if (_ThreadpoolThreadId != GetCurrentThreadId()) + { + WaitForThreadpoolIoCallbacks(threadpoolIo, false); + } + CloseThreadpoolIo(threadpoolIo); + } + + _pValidator = NULL; + + if (_ClientSocket != INVALID_SOCKET) + { + closesocket(_ClientSocket); + _ClientSocket = INVALID_SOCKET; + } + + MethodReturnVoid(); +} + +HRESULT CSocketListener::BeginAccept() +{ + MethodEntry("void"); + + HRESULT hr = S_OK; + _ClientSocket = socket(AF_INET6, SOCK_STREAM, 0); + if (_ClientSocket == INVALID_SOCKET) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + + if (SUCCEEDED(hr)) + { + hr = SetSocketIpv6Only(_ClientSocket, FALSE); + } + + if (SUCCEEDED(hr)) + { + PTP_IO threadpoolIo = _ThreadpoolIo; + if (threadpoolIo != NULL) + { + StartThreadpoolIo(threadpoolIo); + + ULONG_PTR cbReceived = 0; + ZeroMemory(&_Overlapped, sizeof(_Overlapped)); + if (!AcceptEx(_ListenSocket, _ClientSocket, &_AcceptBuffer, + sizeof(_AcceptBuffer.MagicPacket), + sizeof(_AcceptBuffer.DestAddress), + sizeof(_AcceptBuffer.SourceAddress), + (LPDWORD)&cbReceived, &_Overlapped)) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + if (hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING)) + { + // Failed to accept, so cleanup + CancelThreadpoolIo(threadpoolIo); + StopAccepting(); + } + } + } + } + + MethodReturnHR(hr); +} + +void CSocketListener::AcceptThreadProc(_In_ HRESULT hr, _In_ ULONG_PTR cbReceived) +{ + MethodEntry("hr = %!HRESULT!, cbReceived = %d", + hr, (ULONG)cbReceived); + + if (SUCCEEDED(hr)) + { + if (cbReceived == sizeof(_AcceptBuffer.MagicPacket)) + { + // Transfer ownership of _ClientSocket + _pValidator->ValidateAccept(_ClientSocket, &_AcceptBuffer.MagicPacket); + } + else + { + // Wrong header size, close immediately + closesocket(_ClientSocket); + } + _ClientSocket = INVALID_SOCKET; + } + + // Start up another accept request + BeginAccept(); + + MethodReturnVoid(); +} + +HRESULT CSocketListener::Bind() +{ + MethodEntry("void"); + + // Create a SOCKET for connecting to this server + HRESULT hr = S_OK; + addrinfoW* pResult = NULL; + addrinfoW Hints = {}; + Hints.ai_family = AF_INET6; + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_flags = AI_PASSIVE; + + // Resolve the server address and port + if (GetAddrInfoW(NULL, L"9299", &Hints, &pResult) != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + + if (SUCCEEDED(hr)) + { + // Create a SOCKET for connecting to server + _ListenSocket = socket(AF_INET6, SOCK_STREAM, 0); + if (_ListenSocket == INVALID_SOCKET) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + + if (SUCCEEDED(hr)) + { + hr = SetSocketIpv6Only(_ListenSocket, FALSE); + } + + if (SUCCEEDED(hr)) + { + // Setup the TCP listening socket + if (bind(_ListenSocket, pResult->ai_addr, (int)pResult->ai_addrlen) == SOCKET_ERROR) + { + hr = HRESULT_FROM_WIN32(WSAGetLastError()); + } + } + FreeAddrInfoW(pResult); + } + + MethodReturnHR(hr); +} + diff --git a/nfp/net/driver/socketlistener.h b/nfp/net/driver/socketlistener.h new file mode 100644 index 00000000..dffb11a2 --- /dev/null +++ b/nfp/net/driver/socketlistener.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Abstract: + + Declares a socket listener class + +Author: + + Travis Martin (TravM) 06-24-2010 + +Environment: + + User-mode only. + +--*/ +#pragma once + +struct ACCEPT_BUFFER +{ + GUID MagicPacket; + + SOCKADDR_STORAGE DestAddress; + SOCKADDR_STORAGE SourceAddress; +}; + +interface IValidateAccept +{ + virtual void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket) = 0; +}; + +class CSocketListener +{ +public: + CSocketListener() : + _pValidator(NULL), + _ThreadpoolIo(NULL), + _ListenSocket(INVALID_SOCKET), + _ClientSocket(INVALID_SOCKET) + { + ZeroMemory(&_Overlapped, sizeof(_Overlapped)); + } + + ~CSocketListener() + { + StopAccepting(); + } + +public: + HRESULT Bind(); + HRESULT EnableAccepting(_In_ IValidateAccept* pValidator); + void StopAccepting(); + +private: + + HRESULT BeginAccept(); + void AcceptThreadProc(_In_ HRESULT hr, _In_ ULONG_PTR cbReceived); + static void CALLBACK s_AcceptThreadProc( + _Inout_ PTP_CALLBACK_INSTANCE /*Instance*/, + _Inout_ PVOID Context, + _Inout_opt_ PVOID /*Overlapped*/, + _In_ ULONG IoResult, + _In_ ULONG_PTR NumberOfBytesTransferred, + _Inout_ PTP_IO /*Io*/) + { + CSocketListener* pSocketListener = (CSocketListener*)Context; + pSocketListener->_ThreadpoolThreadId = GetCurrentThreadId(); + pSocketListener->AcceptThreadProc(HRESULT_FROM_WIN32(IoResult), NumberOfBytesTransferred); + pSocketListener->_ThreadpoolThreadId = 0; + } + +private: + ACCEPT_BUFFER _AcceptBuffer; + + OVERLAPPED _Overlapped; + volatile PTP_IO _ThreadpoolIo; + DWORD _ThreadpoolThreadId; + + IValidateAccept* _pValidator; + + SOCKET _ListenSocket; + SOCKET _ClientSocket; +}; diff --git a/nfp/net/driver/wppdefs.h b/nfp/net/driver/wppdefs.h new file mode 100644 index 00000000..da0a176e --- /dev/null +++ b/nfp/net/driver/wppdefs.h @@ -0,0 +1,452 @@ +/*++ + +Copyright (c) Microsoft Corporation. All Rights Reserved + +Abstract: + + WPP Macro definitions. + +Author: + + Travis Martin (TravM) + +--*/ + +// +// Helpful macros +// + +#ifndef WIDEN2 +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) +#endif + + +// +// WPP definitions. Listed below is a set of WPP Trace macros. The comments +// between "//begin_wpp config" and "//end_wpp" are used by the WPP pre-processor +// to create the *.tmh files +// + + +#define PROXIMITY_COMMON_TRACE L"Microsoft\\Windows\\ProximityCommon" + +#ifndef TRACE_CONTROL_GUID +#define TRACE_CONTROL_GUID (93bfc19b, a967, 4339, a3e6, 3a4cc30681d1) +#endif + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(PROXIMITY, TRACE_CONTROL_GUID, \ + WPP_DEFINE_BIT(EntryExit) \ + WPP_DEFINE_BIT(AllocFree) \ + WPP_DEFINE_BIT(Info) \ + WPP_DEFINE_BIT(Warning) \ + WPP_DEFINE_BIT(Error) \ + \ + WPP_DEFINE_BIT(NoisyEntryExit) \ + WPP_DEFINE_BIT(NoisyAllocFree) \ + WPP_DEFINE_BIT(NoisyInfo) \ + WPP_DEFINE_BIT(NoisyWarning)) + + +// +// Used for trace messages indentation +// +const char __indentSpacer[] = +" " +" " +" " +" " +" " +" "; + +#define INDENT_STR(indent) \ + (__indentSpacer + ((sizeof(__indentSpacer) >= (indent)*5) ? (sizeof(__indentSpacer)-2-(indent)*5) : 0)) + + +//--------------------------------------------------------------------------- +// Stores a pointer to current tracing context +//--------------------------------------------------------------------------- +extern DWORD __g_tracingTlsSlot; + +//--------------------------------------------------------------------------- +// This macro declares the global variable that will store TLS index for the +// tracing context pointer. +//--------------------------------------------------------------------------- +#define DECLARE_TRACING_TLS DWORD __g_tracingTlsSlot = TLS_OUT_OF_INDEXES + +//--------------------------------------------------------------------------- +// To be used only within non-WDTF EXE init routines or by the Tracer. +//--------------------------------------------------------------------------- +inline bool TracingTlsInitialize() +{ + if (__g_tracingTlsSlot == TLS_OUT_OF_INDEXES) + { + __g_tracingTlsSlot = TlsAlloc(); + if (__g_tracingTlsSlot == TLS_OUT_OF_INDEXES) + { + // Return error: cannot allocate TLS slot + return false; + } + } + return true; +} + +//--------------------------------------------------------------------------- +// To be used only within non-WDTF EXE exit routines or by the Tracer. +//--------------------------------------------------------------------------- +inline void TracingTlsFree() +{ + if (__g_tracingTlsSlot != TLS_OUT_OF_INDEXES) + { + TlsFree(__g_tracingTlsSlot); + __g_tracingTlsSlot = TLS_OUT_OF_INDEXES; + } +} + + +namespace TracingInternal +{ + +//--------------------------------------------------------------------------- +// Used for storing current tracing context within a TLS slot +//--------------------------------------------------------------------------- +struct TracingContext +{ + ULONG CallDepth; // Current depth of internal calls + DWORD Context; // A context value (used to correlate scenarios that cross-threads) +}; + +//--------------------------------------------------------------------------- +// Auto-incrementing and decrementing variable +//--------------------------------------------------------------------------- +class AutoStackDepth +{ +public: + __forceinline AutoStackDepth(ULONG *pCallDepth) + : _pCallDepth(pCallDepth) + { + WUDF_SAMPLE_DRIVER_ASSERT(_pCallDepth); + if (_pCallDepth) + { + ++*_pCallDepth; + } + } + + __forceinline ~AutoStackDepth() + { + if (_pCallDepth) + { + --*_pCallDepth; + } + } + +private: + AutoStackDepth(AutoStackDepth& rh); + const AutoStackDepth& operator =(AutoStackDepth& rh); + +private: + ULONG* _pCallDepth; +}; + +//--------------------------------------------------------------------------- +// Sets new value to a variable but saves old value and restores it on +// destrutcion +//--------------------------------------------------------------------------- +template <class T> +class AutoRestoredValue +{ +public: + __forceinline AutoRestoredValue(T* pVar, T newVal) + : _pVar(pVar) + , _oldVal() + { + WUDF_SAMPLE_DRIVER_ASSERT(_pVar); + if (_pVar) + { + _oldVal = *_pVar; + *_pVar = newVal; + } + } + + __forceinline ~AutoRestoredValue() + { + if (_pVar) + { + *_pVar = _oldVal; + } + } + +private: + AutoRestoredValue(AutoRestoredValue& rh); + const AutoRestoredValue& operator =(AutoRestoredValue& rh); + +private: + + T* _pVar; + T _oldVal; +}; + +//--------------------------------------------------------------------------- +// Auto-pointer stored in TLS +//--------------------------------------------------------------------------- +template <class Pointee> +class AutoTlsPtr +{ +public: + __forceinline AutoTlsPtr() + : _dwSlotIndex(TLS_OUT_OF_INDEXES) + { + } + + __forceinline ~AutoTlsPtr() + { + if (_dwSlotIndex != TLS_OUT_OF_INDEXES) + { + LPVOID pCtx = TlsGetValue(_dwSlotIndex); + if (pCtx) + { + TlsSetValue(_dwSlotIndex, NULL); + } + } + } + + __forceinline Attach(Pointee* pCtx, DWORD dwSlotIndex) + { + _dwSlotIndex = dwSlotIndex; + TlsSetValue(_dwSlotIndex, pCtx); + } + +private: + + DWORD _dwSlotIndex; +}; + +} + + +//--------------------------------------------------------------------------- +// This macro should be used at entry point of all functions with tracing. +// It reads from a Tracing context structure stored in the TLS. +// If the slot contains a NULL a new TracingContext is used. An object +// is created that increments CallDepth and auto-decrements it on function exit. +//--------------------------------------------------------------------------- +#define USE_DEFAULT_TRACING_CONTEXT \ + TracingInternal::TracingContext* __pCtx = (TracingInternal::TracingContext*)TlsGetValue(__g_tracingTlsSlot); \ + TracingInternal::AutoTlsPtr<TracingInternal::TracingContext> __autoTlsPtr; \ + TracingInternal::TracingContext __ctx; \ + if (__pCtx == NULL) \ + { \ + __pCtx = &__ctx; \ + __pCtx->CallDepth = 0; \ + __autoTlsPtr.Attach(__pCtx, __g_tracingTlsSlot); \ + } \ + TracingInternal::AutoStackDepth __autoStackDepth(&__pCtx->CallDepth); + + +//MACRO: MethodEntry +// +//begin_wpp config +//USEPREFIX (MethodEntry, "%!STDPREFIX!%s-->this(%p):%!FUNC!(", INDENT_STR(__pCtx->CallDepth), this); +//FUNC MethodEntry{ENTRYLEVEL=EntryExit}(MSG, ...); +//USESUFFIX (MethodEntry, ")"); +//end_wpp +#define WPP_ENTRYLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_ENTRYLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_ENTRYLEVEL_PRE(LEVEL) USE_DEFAULT_TRACING_CONTEXT; + + +//MACRO: MethodReturn +// +//begin_wpp config +//USEPREFIX (MethodReturn, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): ", INDENT_STR(__pCtx->CallDepth), this); +//FUNC MethodReturn{RETURNLEVEL=EntryExit}(RET, MSG, ...); +//end_wpp +#define WPP_RETURNLEVEL_RET_ENABLED(LEVEL, Ret) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_RETURNLEVEL_RET_LOGGER(LEVEL, Ret) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_RETURNLEVEL_RET_POST(LEVEL, Ret) ;return Ret; + + +//MACRO: MethodReturnHR +// +//begin_wpp config +//USEPREFIX (MethodReturnHR, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!HRESULT!", INDENT_STR(__pCtx->CallDepth), this, __hr); +//FUNC MethodReturnHR{RETURNHRLEVEL=EntryExit}(HR); +//end_wpp +#define WPP_RETURNHRLEVEL_HR_ENABLED(LEVEL, hr) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_RETURNHRLEVEL_HR_LOGGER(LEVEL, hr) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_RETURNHRLEVEL_HR_PRE(LEVEL, hr) { \ + HRESULT __hr = hr; +#define WPP_RETURNHRLEVEL_HR_POST(LEVEL, hr) /*TraceMessage()*/; \ + return __hr; \ + } +//MACRO: MethodReturnVoid +// +//begin_wpp config +//USEPREFIX (MethodReturnVoid, "%!STDPREFIX!%s<--this(%p):%!FUNC!()", INDENT_STR(__pCtx->CallDepth), this); +//FUNC MethodReturnVoid{RETURNVOIDLEVEL=EntryExit}(...); +//end_wpp +#define WPP_RETURNVOIDLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_RETURNVOIDLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_RETURNVOIDLEVEL_POST(LEVEL) ;return; + + +//MACRO: MethodReturnBool +// +//begin_wpp config +//USEPREFIX (MethodReturnBool, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!bool!", INDENT_STR(__pCtx->CallDepth), this, __bRet); +//FUNC MethodReturnBool{RETURNBOOLLEVEL=EntryExit}(BOOLRETVAL); +//end_wpp +#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_ENABLED(LEVEL, bRet) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_LOGGER(LEVEL, bRet) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_PRE(LEVEL, bRet) { \ + bool __bRet = (bRet ? true : false); +#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_POST(LEVEL, bRet) /*TraceMessage()*/; \ + return __bRet; \ + } +//MACRO: MethodReturnPtr +// +//begin_wpp config +//USEPREFIX (MethodReturnPtr, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): %p", INDENT_STR(__pCtx->CallDepth), this, __ptrRetVal); +//FUNC MethodReturnPtr{RETURNPTRLEVEL=EntryExit}(TYPE, PRET); +//end_wpp +#define WPP_RETURNPTRLEVEL_TYPE_PRET_ENABLED(LEVEL, Type, pRet) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_RETURNPTRLEVEL_TYPE_PRET_LOGGER(LEVEL, Type, pRet) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_RETURNPTRLEVEL_TYPE_PRET_PRE(LEVEL, Type, pRet) { \ + Type __pRet = pRet; +#define WPP_RETURNPTRLEVEL_TYPE_PRET_POST(LEVEL, Type, pRet) /*TraceMessage()*/; \ + return __pRet; \ + } +//MACRO: MethodReturnIfNull +// +//begin_wpp config +//USEPREFIX (MethodReturnIfNull, "%!STDPREFIX!%s<-this(%p):%!FUNC!(): E_POINTER %s=NULL, bailing out!", INDENT_STR(__pCtx->CallDepth), this, #PTR); +//FUNC MethodReturnIfNull{METHOD_POINTER_LEVEL=EntryExit}(PTR); +//end_wpp +#define WPP_METHOD_POINTER_LEVEL_PTR_ENABLED(LEVEL, PTR) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_METHOD_POINTER_LEVEL_PTR_LOGGER(LEVEL, PTR) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_METHOD_POINTER_LEVEL_PTR_PRE(LEVEL, PTR) if ((PTR) == NULL) \ + { +#define WPP_METHOD_POINTER_LEVEL_PTR_POST(LEVEL, PTR) /*TraceMessage()*/; \ + return E_POINTER; \ + } +//MACRO: FunctionEntry +// +//begin_wpp config +//USEPREFIX (FunctionEntry, "%!STDPREFIX!%s-->%!FUNC!(", INDENT_STR(__pCtx->CallDepth)); +//FUNC FunctionEntry{FUNCENTRYLEVEL=EntryExit}(MSG, ...); +//USESUFFIX (FunctionEntry, ")"); +//end_wpp +#define WPP_FUNCENTRYLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_FUNCENTRYLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_FUNCENTRYLEVEL_PRE(LEVEL) USE_DEFAULT_TRACING_CONTEXT; + + +//MACRO: FunctionReturn +// +//begin_wpp config +//USEPREFIX (FunctionReturn, "%!STDPREFIX!%s<--%!FUNC!(): ", INDENT_STR(__pCtx->CallDepth)); +//FUNC FunctionReturn{FUNCRETURNLEVEL=EntryExit}(RET, MSG, ...); +//end_wpp +#define WPP_FUNCRETURNLEVEL_RET_ENABLED(LEVEL, Ret) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_FUNCRETURNLEVEL_RET_LOGGER(LEVEL, Ret) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_FUNCRETURNLEVEL_RET_POST(LEVEL, Ret) ;return Ret; + + +//MACRO: FunctionReturnHR +// +//begin_wpp config +//USEPREFIX (FunctionReturnHR, "%!STDPREFIX!%s<--%!FUNC!(): %!HRESULT!", INDENT_STR(__pCtx->CallDepth), __hr); +//FUNC FunctionReturnHR{FUNCRETURNHRLEVEL=EntryExit}(HR); +//end_wpp +#define WPP_FUNCRETURNHRLEVEL_HR_ENABLED(LEVEL, hr) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_FUNCRETURNHRLEVEL_HR_LOGGER(LEVEL, hr) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_FUNCRETURNHRLEVEL_HR_PRE(LEVEL, hr) { \ + HRESULT __hr = hr; +#define WPP_FUNCRETURNHRLEVEL_HR_POST(LEVEL, hr) /*TraceMessage()*/; \ + return __hr; \ + } +//MACRO: FunctionReturnVoid +// +//begin_wpp config +//USEPREFIX (FunctionReturnVoid, "%!STDPREFIX!%s<--%!FUNC!()", INDENT_STR(__pCtx->CallDepth)); +//FUNC FunctionReturnVoid{FUNCRETURNLEVELVOID=EntryExit}(...); +//end_wpp +#define WPP_FUNCRETURNLEVELVOID_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_FUNCRETURNLEVELVOID_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_FUNCRETURNLEVELVOID_POST(LEVEL) ;return; + + +//MACRO: FunctionReturnBool +// +//begin_wpp config +//USEPREFIX (FunctionReturnBool, "%!STDPREFIX!%s<--%!FUNC!(): %!bool!", INDENT_STR(__pCtx->CallDepth), __bRet); +//FUNC FunctionReturnBool{FUNCRETURNLEVELBOOL=EntryExit}(BOOLRETVAL); +//end_wpp +#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_ENABLED(LEVEL, bRet) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_LOGGER(LEVEL, bRet) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_PRE(LEVEL, bRet) { \ + bool __bRet = (bRet ? true : false); +#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_POST(LEVEL, bRet) /*TraceMessage()*/; \ + return __bRet; \ + } +//MACRO: FunctionReturnPtr +// +//begin_wpp config +//USEPREFIX (FunctionReturnPtr, "%!STDPREFIX!%s<--%!FUNC!(): %p", INDENT_STR(__pCtx->CallDepth), __pRet); +//FUNC FunctionReturnPtr{FUNCRETURNLEVELPTR=EntryExit}(TYPE, PRET); +//end_wpp +#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_ENABLED(LEVEL, Type, pRet) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_LOGGER(LEVEL, Type, pRet) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_PRE(LEVEL, Type, pRet) { \ + Type __pRet = pRet; +#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_POST(LEVEL, Type, pRet) /*TraceMessage()*/; \ + return __pRet; \ + } + + + +// Define Non-empty debug break for checked builds only +#ifndef NDEBUG + #define DEBUG_BREAK() __debugbreak() +#else + #define DEBUG_BREAK() do {} while (false) +#endif + + +//MACRO: TraceASSERT +// +// ASSERT with tracing +// +//begin_wpp config +//USEPREFIX (TraceASSERT, "%!STDPREFIX!%sWARN: ASSERTION FAILED - expression \"%s\" is false.", INDENT_STR(__pCtx->CallDepth+1), #EXPR); +//FUNC TraceASSERT{ASSERTLEVEL=Warning}(EXPR); +//end_wpp +#define WPP_ASSERTLEVEL_EXPR_ENABLED(LEVEL, EXPR) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_ASSERTLEVEL_EXPR_LOGGER(LEVEL, EXPR) WPP_LEVEL_LOGGER(LEVEL) +#define WPP_ASSERTLEVEL_EXPR_PRE(LEVEL, EXPR) if (!(EXPR)) \ + { +#define WPP_ASSERTLEVEL_EXPR_POST(LEVEL, EXPR) /*TraceMessage()*/; \ + WUDF_SAMPLE_DRIVER_ASSERT(FALSE); \ + } + +//MACRO: TraceErrorHR +// +// ERROR trace +// +//begin_wpp config +//USEPREFIX (TraceErrorHR, "%!STDPREFIX!%sERROR: ", INDENT_STR(__pCtx->CallDepth+1)); +//FUNC TraceErrorHR{ERRORLEVEL=Error}(HR, MSG, ...); +//USESUFFIX (TraceErrorHR, ": %!HRESULT!", HR); +//end_wpp +#define WPP_ERRORLEVEL_HR_ENABLED(LEVEL, HR) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_ERRORLEVEL_HR_LOGGER(LEVEL, HR) WPP_LEVEL_LOGGER(LEVEL) + +//MACRO: TraceInfo +// +//begin_wpp config +//USEPREFIX (TraceInfo, "%!STDPREFIX!%s", INDENT_STR(__pCtx->CallDepth+1)); +//FUNC TraceInfo{INFOLEVEL=Info}(MSG, ...); +//end_wpp +#define WPP_INFOLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL) +#define WPP_INFOLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL)
\ No newline at end of file diff --git a/nfp/net/exe/NetNfpControl.cpp b/nfp/net/exe/NetNfpControl.cpp new file mode 100644 index 00000000..b101d19e --- /dev/null +++ b/nfp/net/exe/NetNfpControl.cpp @@ -0,0 +1,579 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Module Name: NetNfpControl.cpp +// Abstract: Windows Near-field Proximity Test tool. Designed for simulating proximity hardware. +// +// NetNfpControl console app allows control of the NetNfpProvider test driver. +// Both the local and remote machine must have the NetNfpProvider driver installed. +// +// *USAGE* +// NetNfpControl.exe <remoteMachine> [/e] +// NetNfpControl.exe [<remoteMachine>] [/k] +// NetNfpControl.exe /q +// +// Example: NetNfpControl.exe John-PC1 +// The first operating mode allows the user to specify a remote machine name (or IPv6 address) +// that the local machine should connect to and simulate proximity with. After it's connected, +// a simple key-press ends the simulated proximity link. The console app then exits. +// If the option /e is specified, rather than the waiting for a key to be pressed, the tool +// waits for the QUIT_NAMED_EVENT named event to be set. The named event can be set by running +// NetNfpControl.exe /q. +// +// Example: NetNfpControl.exe John-PC1 /k +// A second operating mode keeps the console app running with a Ctrl-F1 hotkey registered. +// This hot key remains registered and functional even when the app is in the background. +// When the hot key is intercepted, a near-field proximity event is simulated directly with +// the specified remote machine. +// Note: The console app needs to be running (only one one machine) to intercept the system hot key. +// +// Example: NetNfpControl.exe /k +// A third operating mode also keeps the console app running with a Ctrl-F1 hotkey registered. +// However, you'll have to run this on two or more machines at the same time. Pressing Ctrl-F1 +// on any two machines at the same time causes the machines to exchange their network name via +// a file on a private share with a special file name. +// - The server share used is hard coded to: \\scratch2\scratch\travm\proxrendezvous\ +// - Either create a file server with these folders shared, or change this to match yours. +// - The file has an effective lifetime of 2 seconds. +// - In the event of a collision (two clients posting an event during the same interval), +// only one client 'wins'. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma region Includes +#include "precomp.h" +#pragma endregion + + +#pragma region Globals +wchar_t g_szMachineName[MAX_PATH]; +PCWSTR g_pszRemoteMachineName = nullptr; +#pragma endregion + +#define QUIT_NAMED_EVENT L"NetNfpControl_Quit_Event" + + +//---------------------------------------------------------------------------------------------------------------------- +// Name: DEVICE_INTERFACE_DETAIL +// Comments: +// +//---------------------------------------------------------------------------------------------------------------------- +///<summary>Device interface details.</summary> +struct DEVICE_INTERFACE_DETAIL +{ + DWORD cbSize; + wchar_t szSymbolicLink[MAX_PATH*2]; +}; + +//---------------------------------------------------------------------------------------------------------------------- +// Name: BeginProximity +// Comments: +// +//---------------------------------------------------------------------------------------------------------------------- +///<summary>Initalizes a proximity event.</summary> +///<remarks> +///</remarks> +HRESULT BeginProximity(_In_ PCWSTR pszName, _Out_ HANDLE* pHandle) +{ + HRESULT hr = S_OK; + LPGUID pGuid = (LPGUID) &GUID_DEVINTERFACE_NETNFP; + + HDEVINFO hDevSet = SetupDiGetClassDevs(pGuid, nullptr, nullptr, (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE)); + if (hDevSet == INVALID_HANDLE_VALUE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + DEVICE_INTERFACE_DETAIL deviceInterfaceDetail = {}; + if (SUCCEEDED(hr)) + { + SP_DEVICE_INTERFACE_DATA devInterfaceData = {sizeof(devInterfaceData)}; + if (!SetupDiEnumDeviceInterfaces(hDevSet, nullptr, pGuid, 0, &devInterfaceData)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + if (SUCCEEDED(hr)) + { + PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)&deviceInterfaceDetail; + pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + if (!SetupDiGetDeviceInterfaceDetail(hDevSet, &devInterfaceData, pDetail, + sizeof(deviceInterfaceDetail), nullptr, nullptr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + SetupDiDestroyDeviceInfoList(hDevSet); + } + + HANDLE hProximity = INVALID_HANDLE_VALUE; + if (SUCCEEDED(hr)) + { + hProximity = CreateFile(deviceInterfaceDetail.szSymbolicLink, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hProximity == INVALID_HANDLE_VALUE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + BEGIN_PROXIMITY_ARGS args = {}; + if (SUCCEEDED(hr)) + { + hr = StringCchCopy(args.szName, MAX_PATH, pszName); + } + + if (SUCCEEDED(hr)) + { + DWORD ignore; + if (!DeviceIoControl(hProximity, IOCTL_BEGIN_PROXIMITY, &args, sizeof(args), nullptr, 0, &ignore, nullptr)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + if (FAILED(hr)) + { + if (hProximity != INVALID_HANDLE_VALUE) + { + CloseHandle(hProximity); + hProximity = INVALID_HANDLE_VALUE; + } + } + + *pHandle = hProximity; + + return hr; +} + +//---------------------------------------------------------------------------------------------------------------------- +// Name: AcquireFileLock +// Comments: +// +//---------------------------------------------------------------------------------------------------------------------- +///<summary>Aquires a lock on a file.</summary> +///<remarks> +///</remarks> +HANDLE AcquireFileLock(PCWSTR pszLockFilePath) +{ + HANDLE hLock = INVALID_HANDLE_VALUE; + for (int i = 0; i < 200; i++) + { + wprintf(L"Attempting to Acquire Lock: %u\n", (DWORD)GetTickCount64()); + hLock = CreateFile(pszLockFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); + if (hLock == INVALID_HANDLE_VALUE) + { + Sleep(50); + } + else + { + wprintf(L"Proximity Lock Acquired: %u\n", (DWORD)GetTickCount64()); + break; + } + } + + if (hLock == INVALID_HANDLE_VALUE) + { + wprintf(L"Proximity Lock Not Acquired, check network connectivity Error = %u.\n", GetLastError()); + } + + return hLock; +} + +//---------------------------------------------------------------------------------------------------------------------- +// Name: Proximity +// Comments: +// +//---------------------------------------------------------------------------------------------------------------------- +///<summary>Initiates a proximity event.</summary> +///<remarks> +///</remarks> +void Proximity() +{ + wprintf(L"Checking For Proximate Device\n"); + + SYSTEMTIME sysTime = {}; + GetLocalTime(&sysTime); + + wchar_t szDirectory[MAX_PATH]; + StringCchPrintf(szDirectory, MAX_PATH, L"\\\\scratch2\\scratch\\travm\\proxrendezvous\\%u%02u%02u-%02u", + sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour); + + CreateDirectory(szDirectory, NULL); + + wchar_t szLockPath[MAX_PATH]; + StringCchPrintf(szLockPath, MAX_PATH, L"%s\\lock.txt", szDirectory); + + HANDLE hLock = AcquireFileLock(szLockPath); + + wchar_t szOtherMachine[MAX_PATH] = {}; + if (hLock != INVALID_HANDLE_VALUE) + { + wprintf(L"looking for available devices in proximity.\n"); + wchar_t szFindPath[MAX_PATH]; + StringCchPrintf(szFindPath, MAX_PATH, L"%s\\*.available", szDirectory); + WIN32_FIND_DATA findData; + HANDLE hFind = FindFirstFile(szFindPath, &findData); + + wchar_t szFilePath[MAX_PATH]; + bool fClient; + if (hFind != INVALID_HANDLE_VALUE) + { + fClient = true; + + wprintf(L"Proximate device found: "); + StringCchPrintf(szFilePath, MAX_PATH, L"%s\\%s", szDirectory, findData.cFileName); + HANDLE hFile = CreateFile(szFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD ignore; + (void)ReadFile(hFile, szOtherMachine, sizeof(szOtherMachine) - sizeof(wchar_t), &ignore, NULL); + szOtherMachine[MAX_PATH-1] = L'\0'; + CloseHandle(hFile); + } + + if (szOtherMachine[0] != L'\0') + { + wprintf(L"%s\n", szOtherMachine); + wchar_t szNewFileName[MAX_PATH]; + StringCchPrintf(szNewFileName, MAX_PATH, L"%s\\%s.%s.%02u%02u", szDirectory, szOtherMachine, g_szMachineName, sysTime.wMinute, sysTime.wSecond); + MoveFile(szFilePath, szNewFileName); + } + } + else + { + fClient = false; + + wprintf(L"No proximate device found yet. Placing proximity marker on share...\n"); + StringCchPrintf(szFilePath, MAX_PATH, L"%s\\%s.available", szDirectory, g_szMachineName); + HANDLE hFile = CreateFile(szFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD ignore; + WriteFile(hFile, g_szMachineName, sizeof(g_szMachineName), &ignore, NULL); + CloseHandle(hFile); + } + + FindClose(hFind); + hFind = INVALID_HANDLE_VALUE; + + CloseHandle(hLock); + DeleteFile(szLockPath); + + if (fClient) + { + HANDLE hProximity; + HRESULT hr = BeginProximity(szOtherMachine, &hProximity); + if (SUCCEEDED(hr)) + { + wprintf(L"In Proximity for 1 second...\n"); + Sleep(1000); + CloseHandle(hProximity); + wprintf(L"Proximity Complete.\n"); + } + else + { + wprintf(L"ERROR: BeginProximity() failed: 0x%x\n", hr); + } + } + else + { + wprintf(L"Other machine will initiate proximity...\n"); + Sleep(2000); + + bool fCompleted = true; + hLock = AcquireFileLock(szLockPath); + if (hLock != INVALID_HANDLE_VALUE) + { + wchar_t szNewFileName[MAX_PATH]; + StringCchPrintf(szNewFileName, MAX_PATH, L"%s\\%s.%02u%02u.expired", szDirectory, g_szMachineName, sysTime.wMinute, sysTime.wSecond); + if (MoveFile(szFilePath, szNewFileName)) + { + fCompleted = false; + } + + CloseHandle(hLock); + DeleteFile(szLockPath); + } + + if (fCompleted) + { + wprintf(L"Proximity Successful!\n"); + } + else + { + wprintf(L"ERROR: Proximity Unsuccessful. No proximate device found!\n"); + } + } + } +} + +//---------------------------------------------------------------------------------------------------------------------- +// Name: WndProc +// Comments: +// +//---------------------------------------------------------------------------------------------------------------------- +///<summary>Windows call-back procedure.</summary> +///<remarks> +///Used to receive call-backs for the Windows system-wide Hot Key's +///</remarks> +LRESULT CALLBACK WndProc( + HWND hwnd, // handle to window + UINT uMsg, // message identifier + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + switch (uMsg) + { + case WM_HOTKEY: + { + if (g_pszRemoteMachineName != nullptr) + { + HANDLE hProximity; + HRESULT hr = BeginProximity(g_pszRemoteMachineName, &hProximity); + if (SUCCEEDED(hr)) + { + wprintf(L"In Proximity for 1 second...\n"); + Sleep(1000); + CloseHandle(hProximity); + wprintf(L"Proximity Complete.\n"); + } + else + { + wprintf(L"ERROR: BeginProximity() failed: 0x%x\n", hr); + } + } + else // No machine name specified, need to check for a name on the share + { + Proximity(); + } + } + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + // + // Process other messages. + // + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } +} + +__analysis_noreturn void Usage() +{ + wprintf(L"Usage: \n"); + wprintf(L" NetNfpControl.exe <Machine Name or IP>\n"); + wprintf(L" NetNfpControl.exe /e <Machine Name or IP>\n"); + wprintf(L" NetNfpControl.exe /q\n"); + wprintf(L" NetNfpControl.exe /k\n"); + wprintf(L" NetNfpControl.exe /k <Machine Name or IP>\n"); + wprintf(L"\n"); + wprintf(L"The /k option registers a hotkey for entering proximity while selfhosting\n"); + wprintf(L"The /e option keeps NetNfpControl.exe running until NetNfpControl.exe /q is called\n" + L" (or until the named event %s is set)\n", QUIT_NAMED_EVENT); + wprintf(L"The /q option sets the the named event %s (and exits), causing \n" + L" all the outstanding instances of 'NetNfpControl.exe /e' to exit\n", QUIT_NAMED_EVENT); + + exit(1); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Name: wmain +// Comments: Main application entry point. +// +//---------------------------------------------------------------------------------------------------------------------- +///<summary>wmain.</summary> +///<remarks> +///Main application entry point. +///</remarks> +int _cdecl wmain(_In_ int argc, _In_reads_(argc) PWSTR* argv) +{ + wprintf(L"\n*** Network NearFieldProvider Control Executable ***\n\n"); + if (argc < 2) + { + Usage(); + } + + bool fUseHotKey = false; + bool fWaitOnNamedEvent = false; + bool fQuitGlobalEventWaiters = false; + + for (int i = 1; i < argc; i++) + { + if ((argv[i][0] == L'/') || (argv[i][0] == L'-')) + { + if ((argv[i][1] == L'k') || (argv[i][1] == L'K')) + { + fUseHotKey = true; + } + else if ((argv[i][1] == L'e') || (argv[i][1] == L'E')) + { + fWaitOnNamedEvent = true; + } + else if ((argv[i][1] == L'q') || (argv[i][1] == L'Q')) + { + fQuitGlobalEventWaiters = true; + } + else + { + wprintf(L"*** Unknown command line argument: '%ws' ***\n\n", argv[i]); + Usage(); + } + } + else + { + if (g_pszRemoteMachineName != nullptr) + { + wprintf(L"*** Can't specify two machine names ***\n\n"); + Usage(); + } + g_pszRemoteMachineName = argv[i]; + } + } + + if (fUseHotKey) + { + if (g_pszRemoteMachineName != nullptr) + { + wprintf(L"Press Ctrl-F1 on this machine to initiate proximity with: '%ws'.\n\n", g_pszRemoteMachineName); + } + else + { + // Dynamic Keyboard hotkey version + wprintf(L"Press Ctrl-F1 on two machines at the same time to initiate proximity.\n\n"); + + DWORD cchMachineName = MAX_PATH; + if (!GetComputerNameEx(ComputerNameNetBIOS, g_szMachineName, &cchMachineName)) + { + return FALSE; + } + } + + // Register the window class for the main window. + WNDCLASS wc = {}; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.hInstance = GetModuleHandle(NULL); + wc.lpszMenuName = L"MainMenu"; + wc.lpszClassName = L"MainWndClass"; + + if (!RegisterClass(&wc)) + { + return FALSE; + } + + // Create the main window. + HWND hwndMain = CreateWindow(L"MainWndClass", L"Sample", + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, + (HMENU) NULL, GetModuleHandle(NULL), (LPVOID) NULL); + + // If the main window cannot be created, terminate + // the application. + if (!hwndMain) + { + return FALSE; + } + + if (!RegisterHotKey(hwndMain, 264334, MOD_CONTROL, VK_F1)) + { + wprintf(L"ERROR: Ctrl-F1 Hotkey already registered!\n"); + return FALSE; + } + + // Start the message loop. + + MSG msg; + BOOL bRet; + while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) + { + if (bRet == -1) + { + // handle the error and possibly exit + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + // Return the exit code to the system. + + return (int)msg.wParam; + + } + else if (fQuitGlobalEventWaiters) + { + HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, QUIT_NAMED_EVENT); + if (NULL != hEvent) + { + wprintf(L"Quitting running instances of NetNfpControl.exe /e <machinename>\n"); + + BOOL bSetErr = SetEvent(hEvent); + if (!bSetErr) + { + wprintf(L"Failed to set named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, GetLastError()); + } + + CloseHandle(hEvent); + } + else + { + wprintf(L"Failed to open named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, GetLastError()); + } + } + else + { + if (NULL == g_pszRemoteMachineName) + { + Usage(); + } + + wprintf(L"Attempting connect: '%ws' ...\n\n", g_pszRemoteMachineName); + + HANDLE hProximity; + HRESULT hr = BeginProximity(g_pszRemoteMachineName, &hProximity); + if (SUCCEEDED(hr)) + { + if (fWaitOnNamedEvent) + { + wprintf(L"run NetNfpControl.exe /q to end Proximity (or Set the named event %s)\n", QUIT_NAMED_EVENT); + + HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, QUIT_NAMED_EVENT); + if (NULL != hEvent) + { + DWORD dwWaitErr = WaitForSingleObject(hEvent, INFINITE); + if (WAIT_OBJECT_0 != dwWaitErr) + { + dwWaitErr = (WAIT_FAILED == dwWaitErr ? GetLastError() : dwWaitErr); + wprintf(L"Failed to wait on named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, dwWaitErr); + } + + CloseHandle(hEvent); + } + else + { + wprintf(L"Failed to create/open named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, GetLastError()); + } + } + else + { + wprintf(L"Press Any Key to End Proximity.\n"); + (void) _getch(); + wprintf(L"Ending Proximity...\n"); + } + + CloseHandle(hProximity); + } + else + { + wprintf(L"BeginProximity() failed: 0x%x\n", hr); + } + } + + return 0; +} + diff --git a/nfp/net/exe/NetNfpControl.vcxproj b/nfp/net/exe/NetNfpControl.vcxproj new file mode 100644 index 00000000..b2eb94ff --- /dev/null +++ b/nfp/net/exe/NetNfpControl.vcxproj @@ -0,0 +1,262 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{4ABF1B83-9726-45DE-B705-A8458BCB0915}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{B57AFB72-58B6-45CF-8E49-3D56D66A2842}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>NetNfpControl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>NetNfpControl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>NetNfpControl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>NetNfpControl</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="NetNfpControl.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="precompsrc.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/nfp/net/exe/NetNfpControl.vcxproj.Filters b/nfp/net/exe/NetNfpControl.vcxproj.Filters new file mode 100644 index 00000000..c01e6141 --- /dev/null +++ b/nfp/net/exe/NetNfpControl.vcxproj.Filters @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{1C29E1A2-5E3D-4A88-A8C5-2DBBA704EF00}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{5535C5B0-0DF3-4CF2-ACA9-2F899FA6CE1C}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{534D73C8-CECE-4D3E-9B06-469E2C777F49}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="NetNfpControl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="precompsrc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/nfp/net/exe/precomp.h b/nfp/net/exe/precomp.h new file mode 100644 index 00000000..4748bcf8 --- /dev/null +++ b/nfp/net/exe/precomp.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Module Name: precomp.h +// Abstract: +// +// Precompiled header file for the NetNfpControl console app +// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma once + +#ifndef UNICODE +#define UNICODE +#endif + +#ifndef _UNICODE +#define _UNICODE +#endif + +// Windows Headers +#include <windows.h> +#include <Winsock2.h> +#include <Mswsock.h> +#include <Ws2bth.h> +#include <Ws2tcpip.h> +#include <conio.h> +#include <setupapi.h> +#include <tchar.h> +#include <strsafe.h> +#include <winioctl.h> + +// ATL stuff +#include <atlbase.h> + +// Common NetNfp header +#include "NetNfp.h" diff --git a/nfp/net/exe/precompsrc.cpp b/nfp/net/exe/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/nfp/net/exe/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/nfp/net/inc/NetNfp.h b/nfp/net/inc/NetNfp.h new file mode 100644 index 00000000..b891313e --- /dev/null +++ b/nfp/net/inc/NetNfp.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + NetNfp.h + +Abstract: + + This header contains definitions common to the both the NetNfpProvider.sys + driver and the NetNfpControl.exe. + +Environment: + + User Mode + +--*/ +#pragma once + + +/* 2DD081BE-1294-440B-AB9F-F0E9FDD77FBE */ +const GUID GUID_DEVINTERFACE_NETNFP = + {0x2DD081BE, 0x1294, 0x440B, {0xAB, 0x9F, 0xF0, 0xE9, 0xFD, 0xD7, 0x7F, 0xBE}}; + +#define IOCTL_BEGIN_PROXIMITY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS) + +struct BEGIN_PROXIMITY_ARGS +{ + WCHAR szName[MAX_PATH]; // Name or IP address +}; + diff --git a/nfp/net/netnfp.sln b/nfp/net/netnfp.sln new file mode 100644 index 00000000..f8b5f6b2 --- /dev/null +++ b/nfp/net/netnfp.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{6133A073-0A35-45D3-BC68-BA16B0F829D8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{4FD03920-D970-4A51-A2A1-A394DF683A03}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpProvider", "driver\NetNfpProvider.vcxproj", "{756016BF-4187-4482-A0BE-CEE1698BD129}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpControl", "exe\NetNfpControl.vcxproj", "{4ABF1B83-9726-45DE-B705-A8458BCB0915}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|Win32.ActiveCfg = Debug|Win32 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|Win32.Build.0 = Debug|Win32 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|Win32.ActiveCfg = Release|Win32 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|Win32.Build.0 = Release|Win32 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|x64.ActiveCfg = Debug|x64 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|x64.Build.0 = Debug|x64 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|x64.ActiveCfg = Release|x64 + {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|x64.Build.0 = Release|x64 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|Win32.ActiveCfg = Debug|Win32 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|Win32.Build.0 = Debug|Win32 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|Win32.ActiveCfg = Release|Win32 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|Win32.Build.0 = Release|Win32 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|x64.ActiveCfg = Debug|x64 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|x64.Build.0 = Debug|x64 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|x64.ActiveCfg = Release|x64 + {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {756016BF-4187-4482-A0BE-CEE1698BD129} = {6133A073-0A35-45D3-BC68-BA16B0F829D8} + {4ABF1B83-9726-45DE-B705-A8458BCB0915} = {4FD03920-D970-4A51-A2A1-A394DF683A03} + EndGlobalSection +EndGlobal |
