📄 netbiostransport.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <winsock2.h>
#include <iptypes.h>
#include <Iphlpapi.h>
#include <CReg.hxx>
#include <notify.h>
#include <ncb.h>
#include <windev.h>
#include "SMB_Globals.h"
#include "NetbiosTransport.h"
#include "Utils.h"
#include "CriticalSection.h"
#include "nb.h"
using namespace ce;
using namespace NETBIOS_TRANSPORT;
//do any explicit inits for globals setup in the NETBIOS_TRANSPORT
// namespace
//
//
// Running Accepting State
// X During shutdown
// X Error
// X X Normal Use
// Stopped
//
//
LONG NETBIOS_TRANSPORT::g_fIsInited = FALSE;
LONG NETBIOS_TRANSPORT::g_fIsRunning = FALSE;
LONG NETBIOS_TRANSPORT::g_fIsAccepting = FALSE;
// Address change notification globals
USHORT AddressChangeNotification::usID = 0xFF;
SOCKET AddressChangeNotification::s = INVALID_SOCKET;
WSAOVERLAPPED AddressChangeNotification::ov = {0};
// Name change notification
HANDLE NameChangeNotification::h = NULL;
USHORT NameChangeNotification::usID = 0xFFFF;
ce::list<NetBIOSAdapter *> NETBIOS_TRANSPORT::NBAdapterDeleteStack;
ce::list<NetBIOSAdapter *> NETBIOS_TRANSPORT::NBAdapterStack;
ce::list<RecvNode, NETBIOS_CONNECTION_ALLOC > NETBIOS_TRANSPORT::ActiveRecvList;
HANDLE NETBIOS_TRANSPORT::g_hHaltNetbiosTransport = NULL;
CRITICAL_SECTION NETBIOS_TRANSPORT::csAdapterStackList;
CRITICAL_SECTION NETBIOS_TRANSPORT::csSendLock;
CRITICAL_SECTION NETBIOS_TRANSPORT::csActiveRecvListLock;
CRITICAL_SECTION NETBIOS_TRANSPORT::csNCBLock;
ce::fixed_block_allocator<10> NETBIOS_TRANSPORT::g_NCBAllocator; //Use csNCBLock!
extern DWORD SMB_Deinit(DWORD dwClientContext);
extern DWORD SMB_Init(DWORD dwClientContext);
extern VOID SMB_RestartServer();
extern HRESULT StartTCPListenThread(UINT uiIPAddress, BYTE LANA);
extern HRESULT TerminateTCPListenThread(BYTE LANA);
extern HANDLE g_hNetbiosIOCTL;
extern CRITICAL_SECTION g_csDriverLock;
class HostNameWakeUpNode : public WakeUpNode
{
public:
HostNameWakeUpNode() {}
~HostNameWakeUpNode(){}
VOID WakeUp() {
SMB_RestartServer();
}
VOID Terminate() {
}
};
VOID SMBSRVR_IPAddressChanged();
class IpAddressChangedWakeUpNode : public WakeUpNode
{
public:
IpAddressChangedWakeUpNode() {}
~IpAddressChangedWakeUpNode(){}
VOID WakeUp() {
SMBSRVR_IPAddressChanged();
}
VOID Terminate() {
}
};
//
// Globals to the file
HostNameWakeUpNode g_HostNameWakeUpNode;
IpAddressChangedWakeUpNode g_IPAddressChangedWakeUpNode;
//
// Forward declare any functions
HRESULT InitLana(UCHAR ulLANIdx, DWORD dwNTE);
static void NetBIOSNotifyFunc(uchar lananum, DWORD dwNTE, int flags, int unused);
HRESULT NB_TerminateSession(ULONG ulConnectionID)
{
CCritSection csLock(&csActiveRecvListLock);
HRESULT hr = E_FAIL;
ce::list<RecvNode, NETBIOS_CONNECTION_ALLOC >::iterator itARList;
//
// See if we can find this connection ID
csLock.Lock();
for(itARList=ActiveRecvList.begin(); itARList!=ActiveRecvList.end(); itARList++) {
ce::list<ULONG>::iterator itConn;
for(itConn=(*itARList).OutStandingConnectionIDs.begin(); itConn!=(*itARList).OutStandingConnectionIDs.end(); itConn++) {
if((*itConn) == ulConnectionID) {
BYTE ret;
ncb myNCB;
myNCB.ncb_command = NCBHANGUP;
myNCB.ncb_lsn = (*itARList).usLSN;
myNCB.ncb_lana_num = (*itARList).LANA;
myNCB.ncb_length = 0;
myNCB.ncb_buffer = NULL;
TRACEMSG(ZONE_NETBIOS, (L"SMB_SRV: TerminateSession Called on Netbios for connID: %d", ulConnectionID));
ret = Netbios(&myNCB);
ASSERT(0 == ret);
hr = S_OK;
goto Done;
}
}
}
Done:
return hr;
}
NetBIOSAdapter::NetBIOSAdapter(BYTE _bLana) : bLana(_bLana), nameNum(0xFF), fStopped(FALSE), bMark(TRUE)
{
HRESULT hr = E_FAIL;
RETAILMSG(1, (TEXT("SMBSRV:InitLana: Starting NetBios at index: %d"), bLana));
//
// Init state by zeroing out threads
hListenThread = NULL;
//
// Spin threads to handle listening and recving
hListenThread = CreateThread(NULL, 0, SMBSRVR_NetbiosListenThread, (LPVOID)this, CREATE_SUSPENDED, NULL);
if(NULL == hListenThread) {
TRACEMSG(ZONE_ERROR, (TEXT("SMBSRV:InitLana: CreateThread failed starting NB Listen:%d"), GetLastError()));
goto Done;
}
ASSERT(FAILED(hr));
hr = S_OK;
Done:
//
// If we failed, set the shutdown flag
if(FAILED(hr)) {
InterlockedExchange(&fStopped,TRUE);
}
//
// Now crank up all threads (if we error'ed they will all just return quickly)
if(NULL != hListenThread) {
if(0xFFFFFFFF == ResumeThread(hListenThread)) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV:Resuming listen thread %d FAILED!"));
CloseHandle(hListenThread);
hListenThread = NULL; //Createthread returns null, not invalid handle value!
}
}
}
NetBIOSAdapter::~NetBIOSAdapter()
{
//
// If the adapter is running, kill it off
if(!fStopped && FAILED(HaltAdapter())) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV: NetBIOSAdapter halting failed! (idx:%d)", this->bLana));
ASSERT(FALSE);
}
}
HRESULT
NetBIOSAdapter::HaltAdapter()
{
ncb tNcb;
BYTE *pCName;
UCHAR retVal;
HRESULT hr = S_OK;
ce::list<RecvNode, NETBIOS_CONNECTION_ALLOC >::iterator itARList;
CCritSection csLock(&csActiveRecvListLock);
if(TRUE == fStopped) {
return S_OK;
}
//
// Render the sending thread worthless
InterlockedExchange(&fStopped, TRUE);
//
// Get registered CName
if(FAILED(hr = this->GetCName(&pCName))) {
TRACEMSG(ZONE_ERROR, (TEXT("SMBSRV:InitLana: couldnt get CName")));
goto Done;
}
//
// Hangup anything thats on our LANA;
csLock.Lock();
for(itARList=ActiveRecvList.begin(); itARList!=ActiveRecvList.end(); itARList++) {
//
// If this is on our LANA, hang it up (this should stop any active connections)
if((*itARList).LANA == bLana) {
tNcb.ncb_command = NCBHANGUP;
tNcb.ncb_lana_num = bLana;
tNcb.ncb_lsn = (*itARList).usLSN;
memcpy(tNcb.ncb_name, pCName, 16);
tNcb.ncb_length = 0;
tNcb.ncb_buffer = NULL;
retVal = Netbios(&tNcb);
if (retVal != 0 || (retVal = tNcb.ncb_retcode) != 0) {
TRACEMSG(ZONE_ERROR, (TEXT("SMBSRV:InitLana: NCBHANGUPANY returned %s"), NETBIOS_TRANSPORT::NCBError(retVal)));
}
}
}
csLock.UnLock();
//
// Un-register the name
tNcb.ncb_command = NCBDELNAME;
tNcb.ncb_lana_num = bLana;
tNcb.ncb_length = 0;
tNcb.ncb_buffer = NULL;
memcpy(tNcb.ncb_name, pCName, 16);
retVal = Netbios(&tNcb);
if (retVal != 0 || (retVal = tNcb.ncb_retcode) != 0) {
TRACEMSG(ZONE_ERROR, (TEXT("SMBSRV:InitLana: NCBDELNAME returned %s"), NETBIOS_TRANSPORT::NCBError(retVal)));
}
//
// Wait for the listening thread to stop
if(WAIT_FAILED == WaitForSingleObject(hListenThread, INFINITE)) {
TRACEMSG(ZONE_INIT, (L"SMBSRV:Waiting for LISTEN thread FAILED!"));
ASSERT(FALSE);
hr = E_FAIL;
}
TRACEMSG(ZONE_INIT, (L"SMBSRV:Listen thread has been stopped!"));
//
// Wait for the recving threads to stop
for(;;) {
csLock.Lock();
if(0 == ActiveRecvList.size()) {
break;
}
RecvNode *myNode = &(ActiveRecvList.front());
HANDLE h = myNode->MyHandle;
csLock.UnLock();
if(WAIT_FAILED == WaitForSingleObject(h, INFINITE)) {
TRACEMSG(ZONE_INIT, (L"SMBSRV:Waiting for RECV thread FAILED!"));
ASSERT(FALSE);
}
}
TRACEMSG(ZONE_INIT, (L"SMBSRV:Recv threads have been stopped!"));
Done:
return hr;
}
BOOL
NetBIOSAdapter::DuringShutDown()
{
//
// We are in the process of shutting down when we are running
// but not accepting
return fStopped;
}
CHAR GetLANAFromNTE(DWORD dwNTE)
{
NCB ncb;
if(NB_FAILURE == NETbiosThunk(0, NB_CONVERT_NTE_TO_LANA, (PBYTE)&ncb, sizeof(dwNTE), (PBYTE)&dwNTE, 0, NULL)) {
return (CHAR)0xFF;
} else {
return (CHAR)dwNTE;
}
}
const int MAX_QUERY_ATTEMPTS = 3;
DWORD
GetAdaptersInformation(CHAR** ppAdapterInfo, DWORD dwNeeded, DWORD *pdwAdapterInfo)
{
DWORD dwRetCode = ERROR_SUCCESS;
CHAR* pPassedInPtr = *ppAdapterInfo;
ASSERT(pdwAdapterInfo);
ASSERT(ppAdapterInfo);
ASSERT(*ppAdapterInfo);
//
// Because we are awake, enum all IP addresses
for(int i=0; i<MAX_QUERY_ATTEMPTS; i++) {
if(ERROR_BUFFER_OVERFLOW == (dwRetCode = GetAdaptersInfo((IP_ADAPTER_INFO *)*ppAdapterInfo, &dwNeeded))) {
if(pPassedInPtr != *ppAdapterInfo) {
delete [] *ppAdapterInfo;
}
if(NULL == (*ppAdapterInfo = new CHAR[dwNeeded])) {
dwRetCode = ERROR_OUTOFMEMORY;
goto Done;
}
*pdwAdapterInfo = dwNeeded;
}
else if(NO_ERROR == dwRetCode || ERROR_NO_DATA == dwRetCode) {
break;
}
}
Done:
if((dwRetCode != NO_ERROR) && (pPassedInPtr != *ppAdapterInfo)) {
delete [] *ppAdapterInfo;
*ppAdapterInfo = NULL;
}
return dwRetCode;
}
VOID
SMBSRVR_IPAddressChanged() {
ASSERT(NULL != g_hHaltNetbiosTransport);
CHAR AdapterInfo[1024];
CHAR *pAdapterInfo = AdapterInfo;
DWORD dwAdapterInfo = sizeof(AdapterInfo);
DWORD dwRetCode = 0;
DWORD dwNeeded = 0;
DWORD dwWaitRet = 0;
IP_ADAPTER_INFO *pAdaptTemp = NULL;
CCritSection csLock(&csAdapterStackList);
ce::list<NetBIOSAdapter *>::iterator itAdapt;
//
// Refresh the event
if(ERROR_SUCCESS != WSAIoctl(AddressChangeNotification::s, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, NULL, &AddressChangeNotification::ov, NULL) &&
ERROR_IO_PENDING != GetLastError()) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV:IP Adapter change error -- cant call ioctl with SIO_ADDRESS_LIST_CHANGE"));
ASSERT(FALSE);
goto Done;
}
//
// Because we are awake, enum all IP addresses
dwNeeded = dwAdapterInfo;
dwRetCode = GetAdaptersInformation(&pAdapterInfo, dwNeeded, &dwAdapterInfo);
if(NO_ERROR != dwRetCode) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV:Unable to get adapter information [%d]", dwRetCode));
goto Done;
}
//
// Using the addresses loop over what we already have and whats there now
// deleting/adding as we go
pAdaptTemp = (IP_ADAPTER_INFO *)pAdapterInfo;
csLock.Lock();
// Set everyones mark false (MARK phase)
for(itAdapt=NBAdapterStack.begin(); itAdapt!=NBAdapterStack.end(); ++itAdapt) {
(*itAdapt)->SetMark(FALSE);
}
while(NULL != pAdaptTemp) {
BOOL fFound = FALSE;
// Loop looking for our NTE, if we find it, mark the node
for(itAdapt=NBAdapterStack.begin(); itAdapt!=NBAdapterStack.end(); ++itAdapt) {
if((*itAdapt)->GetNTE() == pAdaptTemp->CurrentIpAddress->Context) {
fFound = TRUE;
if(0 != strcmp("0.0.0.0", pAdaptTemp->CurrentIpAddress->IpAddress.String)) {
(*itAdapt)->SetMark(TRUE);
}
break;
}
}
// if we didnt find the node its NEW, call our notify funct with the proper lana
if(!fFound) {
DWORD dwLANA = GetLANAFromNTE(pAdaptTemp->CurrentIpAddress->Context);
if(0xFFFFFFFF == dwLANA) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV: invalid LANA on context %d, maybe the IP isnt valid? ", pAdaptTemp->CurrentIpAddress->Context));
} else {
NetBIOSNotifyFunc((CHAR)dwLANA, pAdaptTemp->CurrentIpAddress->Context, LANA_UP_FL, 0);
}
}
pAdaptTemp = pAdaptTemp->Next;
}
// Delete all nodes that are not marked (SWEEP phase)
BOOL fNeedPurge = FALSE;
for(itAdapt=NBAdapterStack.begin(); itAdapt!=NBAdapterStack.end();) {
if(FALSE == (*itAdapt)->GetMark()) {
if(!NBAdapterDeleteStack.push_front((*itAdapt))) {
goto Done;
}
NBAdapterStack.erase(itAdapt++);
fNeedPurge = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -