📄 nbt.c
字号:
}
typedef struct _NetBTNameQueryData {
NBNameCacheEntry *cacheEntry;
UCHAR ret;
} NetBTNameQueryData;
/* Name query callback function for NetBTWaitForNameResponse, creates a cache
* entry on the first answer, adds each address as it's called again (as long
* as there's space). If there's an error that should be propagated as the
* NetBIOS error, modifies queryData's ret member to the proper return code.
*/
static BOOL NetBTFindNameAnswerCallback(void *pVoid, WORD answerCount,
WORD answerIndex, PUCHAR rData, WORD rLen)
{
NetBTNameQueryData *queryData = (NetBTNameQueryData *)pVoid;
BOOL ret;
if (queryData)
{
if (queryData->cacheEntry == NULL)
{
queryData->cacheEntry = HeapAlloc(
GetProcessHeap(), 0, sizeof(NBNameCacheEntry) +
(answerCount - 1) * sizeof(DWORD));
if (queryData->cacheEntry)
queryData->cacheEntry->numAddresses = 0;
else
{
ret = FALSE;
queryData->ret = NRC_OSRESNOTAV;
}
}
if (rLen == 6 && queryData->cacheEntry &&
queryData->cacheEntry->numAddresses < answerCount)
{
queryData->cacheEntry->addresses[queryData->cacheEntry->
numAddresses++] = *(const DWORD *)(rData + 2);
ret = queryData->cacheEntry->numAddresses < answerCount;
}
else
ret = FALSE;
}
else
ret = FALSE;
return ret;
}
/* Workhorse NetBT name lookup function. Sends a name lookup query for
* ncb->ncb_callname to sendTo, as a broadcast if broadcast is TRUE, using
* adapter->nameQueryXID as the transaction ID. Waits up to timeout
* milliseconds, and retries up to maxQueries times, waiting for a reply.
* If a valid response is received, stores the looked up addresses as a
* NBNameCacheEntry in *cacheEntry.
* Returns NRC_GOODRET on success, though this may not mean the name was
* resolved--check whether *cacheEntry is NULL.
*/
static UCHAR NetBTNameWaitLoop(const NetBTAdapter *adapter, SOCKET fd, const NCB *ncb,
DWORD sendTo, BOOL broadcast, DWORD timeout, DWORD maxQueries,
NBNameCacheEntry **cacheEntry)
{
unsigned int queries;
NetBTNameQueryData queryData;
if (!adapter) return NRC_BADDR;
if (fd == INVALID_SOCKET) return NRC_BADDR;
if (!ncb) return NRC_BADDR;
if (!cacheEntry) return NRC_BADDR;
queryData.cacheEntry = NULL;
queryData.ret = NRC_GOODRET;
for (queries = 0; queryData.cacheEntry == NULL && queries < maxQueries;
queries++)
{
if (!NCB_CANCELLED(ncb))
{
int r = NetBTSendNameQuery(fd, ncb->ncb_callname,
adapter->nameQueryXID, NBNS_TYPE_NB, sendTo, broadcast);
if (r == 0)
queryData.ret = NetBTWaitForNameResponse(adapter, fd,
GetTickCount() + timeout, NetBTFindNameAnswerCallback,
&queryData);
else
queryData.ret = NRC_SYSTEM;
}
else
queryData.ret = NRC_CMDCAN;
}
if (queryData.cacheEntry)
{
memcpy(queryData.cacheEntry->name, ncb->ncb_callname, NCBNAMSZ);
memcpy(queryData.cacheEntry->nbname, ncb->ncb_callname, NCBNAMSZ);
}
*cacheEntry = queryData.cacheEntry;
return queryData.ret;
}
/* Attempts to add cacheEntry to the name cache in *nameCache; if *nameCache
* has not yet been created, creates it, using gCacheTimeout as the cache
* entry timeout. If memory allocation fails, or if NBNameCacheAddEntry fails,
* frees cacheEntry.
* Returns NRC_GOODRET on success, and something else on failure.
*/
static UCHAR NetBTStoreCacheEntry(struct NBNameCache **nameCache,
NBNameCacheEntry *cacheEntry)
{
UCHAR ret;
if (!nameCache) return NRC_BADDR;
if (!cacheEntry) return NRC_BADDR;
if (!*nameCache)
*nameCache = NBNameCacheCreate(GetProcessHeap(), gCacheTimeout);
if (*nameCache)
ret = NBNameCacheAddEntry(*nameCache, cacheEntry)
? NRC_GOODRET : NRC_OSRESNOTAV;
else
{
HeapFree(GetProcessHeap(), 0, cacheEntry);
ret = NRC_OSRESNOTAV;
}
return ret;
}
/* Attempts to resolve name using inet_addr(), then gethostbyname() if
* gEnableDNS is TRUE, if the suffix byte is either <00> or <20>. If the name
* can be looked up, returns 0 and stores the looked up addresses as a
* NBNameCacheEntry in *cacheEntry.
* Returns NRC_GOODRET on success, though this may not mean the name was
* resolved--check whether *cacheEntry is NULL. Returns something else on
* error.
*/
static UCHAR NetBTinetResolve(const UCHAR name[NCBNAMSZ],
NBNameCacheEntry **cacheEntry)
{
UCHAR ret = NRC_GOODRET;
TRACE("name %s, cacheEntry %p\n", name, cacheEntry);
if (!name) return NRC_BADDR;
if (!cacheEntry) return NRC_BADDR;
if (isalnum(name[0]) && (name[NCBNAMSZ - 1] == 0 ||
name[NCBNAMSZ - 1] == 0x20))
{
CHAR toLookup[NCBNAMSZ];
unsigned int i;
for (i = 0; i < NCBNAMSZ - 1 && name[i] && name[i] != ' '; i++)
toLookup[i] = name[i];
toLookup[i] = '\0';
if (isdigit(toLookup[0]))
{
unsigned long addr = inet_addr(toLookup);
if (addr != INADDR_NONE)
{
*cacheEntry = HeapAlloc(GetProcessHeap(),
0, sizeof(NBNameCacheEntry));
if (*cacheEntry)
{
memcpy((*cacheEntry)->name, name, NCBNAMSZ);
memset((*cacheEntry)->nbname, 0, NCBNAMSZ);
(*cacheEntry)->nbname[0] = '*';
(*cacheEntry)->numAddresses = 1;
(*cacheEntry)->addresses[0] = addr;
}
else
ret = NRC_OSRESNOTAV;
}
}
if (gEnableDNS && ret == NRC_GOODRET && !*cacheEntry)
{
struct hostent *host;
if ((host = gethostbyname(toLookup)) != NULL)
{
for (i = 0; ret == NRC_GOODRET && host->h_addr_list &&
host->h_addr_list[i]; i++)
;
if (host->h_addr_list && host->h_addr_list[0])
{
*cacheEntry = HeapAlloc(
GetProcessHeap(), 0, sizeof(NBNameCacheEntry) +
(i - 1) * sizeof(DWORD));
if (*cacheEntry)
{
memcpy((*cacheEntry)->name, name, NCBNAMSZ);
memset((*cacheEntry)->nbname, 0, NCBNAMSZ);
(*cacheEntry)->nbname[0] = '*';
(*cacheEntry)->numAddresses = i;
for (i = 0; i < (*cacheEntry)->numAddresses; i++)
(*cacheEntry)->addresses[i] =
(DWORD)host->h_addr_list[i];
}
else
ret = NRC_OSRESNOTAV;
}
}
}
}
TRACE("returning 0x%02x\n", ret);
return ret;
}
/* Looks up the name in ncb->ncb_callname, first in the name caches (global
* and this adapter's), then using gethostbyname(), next by WINS if configured,
* and finally using broadcast NetBT name resolution. In NBT parlance, this
* makes this an "H-node". Stores an entry in the appropriate name cache for a
* found node, and returns it as *cacheEntry.
* Assumes data, ncb, and cacheEntry are not NULL.
* Returns NRC_GOODRET on success--which doesn't mean the name was resolved,
* just that all name lookup operations completed successfully--and something
* else on failure. *cacheEntry will be NULL if the name was not found.
*/
static UCHAR NetBTInternalFindName(NetBTAdapter *adapter, PNCB ncb,
const NBNameCacheEntry **cacheEntry)
{
UCHAR ret = NRC_GOODRET;
TRACE("adapter %p, ncb %p, cacheEntry %p\n", adapter, ncb, cacheEntry);
if (!cacheEntry) return NRC_BADDR;
*cacheEntry = NULL;
if (!adapter) return NRC_BADDR;
if (!ncb) return NRC_BADDR;
if (ncb->ncb_callname[0] == '*')
ret = NRC_NOWILD;
else
{
*cacheEntry = NBNameCacheFindEntry(gNameCache, ncb->ncb_callname);
if (!*cacheEntry)
*cacheEntry = NBNameCacheFindEntry(adapter->nameCache,
ncb->ncb_callname);
if (!*cacheEntry)
{
NBNameCacheEntry *newEntry = NULL;
ret = NetBTinetResolve(ncb->ncb_callname, &newEntry);
if (ret == NRC_GOODRET && newEntry)
{
ret = NetBTStoreCacheEntry(&gNameCache, newEntry);
if (ret != NRC_GOODRET)
newEntry = NULL;
}
else
{
SOCKET fd = WSASocketA(PF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL,
0, WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
ret = NRC_OSRESNOTAV;
else
{
int winsNdx;
adapter->nameQueryXID++;
for (winsNdx = 0; ret == NRC_GOODRET && *cacheEntry == NULL
&& winsNdx < gNumWINSServers; winsNdx++)
ret = NetBTNameWaitLoop(adapter, fd, ncb,
gWINSServers[winsNdx], FALSE, gWINSQueryTimeout,
gWINSQueries, &newEntry);
if (ret == NRC_GOODRET && newEntry)
{
ret = NetBTStoreCacheEntry(&gNameCache, newEntry);
if (ret != NRC_GOODRET)
newEntry = NULL;
}
if (ret == NRC_GOODRET && *cacheEntry == NULL)
{
DWORD bcastAddr =
adapter->ipr.dwAddr & adapter->ipr.dwMask;
if (adapter->ipr.dwBCastAddr)
bcastAddr |= ~adapter->ipr.dwMask;
ret = NetBTNameWaitLoop(adapter, fd, ncb, bcastAddr,
TRUE, gBCastQueryTimeout, gBCastQueries, &newEntry);
if (ret == NRC_GOODRET && newEntry)
{
ret = NetBTStoreCacheEntry(&adapter->nameCache,
newEntry);
if (ret != NRC_GOODRET)
newEntry = NULL;
}
}
closesocket(fd);
}
}
*cacheEntry = newEntry;
}
}
TRACE("returning 0x%02x\n", ret);
return ret;
}
typedef struct _NetBTNodeQueryData
{
BOOL gotResponse;
PADAPTER_STATUS astat;
WORD astatLen;
} NetBTNodeQueryData;
/* Callback function for NetBTAstatRemote, parses the rData for the node
* status and name list of the remote node. Always returns FALSE, since
* there's never more than one answer we care about in a node status response.
*/
static BOOL NetBTNodeStatusAnswerCallback(void *pVoid, WORD answerCount,
WORD answerIndex, PUCHAR rData, WORD rLen)
{
NetBTNodeQueryData *data = (NetBTNodeQueryData *)pVoid;
if (data && !data->gotResponse && rData && rLen >= 1)
{
/* num names is first byte; each name is NCBNAMSZ + 2 bytes */
if (rLen >= rData[0] * (NCBNAMSZ + 2))
{
WORD i;
PUCHAR src;
PNAME_BUFFER dst;
data->gotResponse = TRUE;
data->astat->name_count = rData[0];
for (i = 0, src = rData + 1,
dst = (PNAME_BUFFER)((PUCHAR)data->astat +
sizeof(ADAPTER_STATUS));
i < data->astat->name_count && src - rData < rLen &&
(PUCHAR)dst - (PUCHAR)data->astat < data->astatLen;
i++, dst++, src += NCBNAMSZ + 2)
{
UCHAR flags = *(src + NCBNAMSZ);
memcpy(dst->name, src, NCBNAMSZ);
/* we won't actually see a registering name in the returned
* response. It's useful to see if no other flags are set; if
* none are, then the name is registered. */
dst->name_flags = REGISTERING;
if (flags & 0x80)
dst->name_flags |= GROUP_NAME;
if (flags & 0x10)
dst->name_flags |= DEREGISTERED;
if (flags & 0x08)
dst->name_flags |= DUPLICATE;
if (dst->name_flags == REGISTERING)
dst->name_flags = REGISTERED;
}
/* arbitrarily set HW type to Ethernet */
data->astat->adapter_type = 0xfe;
if (src - rData < rLen)
memcpy(data->astat->adapter_address, src,
min(rLen - (src - rData), 6));
}
}
return FALSE;
}
/* This uses the WINS timeout and query values, as they're the
* UCAST_REQ_RETRY_TIMEOUT and UCAST_REQ_RETRY_COUNT according to the RFCs.
*/
static UCHAR NetBTAstatRemote(NetBTAdapter *adapter, PNCB ncb)
{
UCHAR ret = NRC_GOODRET;
const NBNameCacheEntry *cacheEntry = NULL;
TRACE("adapter %p, NCB %p\n", adapter, ncb);
if (!adapter) return NRC_BADDR;
if (!ncb) return NRC_INVADDRESS;
ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
if (ret == NRC_GOODRET && cacheEntry)
{
if (cacheEntry->numAddresses > 0)
{
SOCKET fd = WSASocketA(PF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
ret = NRC_OSRESNOTAV;
else
{
NetBTNodeQueryData queryData;
DWORD queries;
PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -