⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nbt.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 4 页
字号:
                adapter->nameQueryXID++;
                astat->name_count = 0;
                queryData.gotResponse = FALSE;
                queryData.astat = astat;
                queryData.astatLen = ncb->ncb_length;
                for (queries = 0; !queryData.gotResponse &&
                 queries < gWINSQueries; queries++)
                {
                    if (!NCB_CANCELLED(ncb))
                    {
                        int r = NetBTSendNameQuery(fd, ncb->ncb_callname,
                         adapter->nameQueryXID, NBNS_TYPE_NBSTAT,
                         cacheEntry->addresses[0], FALSE);

                        if (r == 0)
                            ret = NetBTWaitForNameResponse(adapter, fd,
                             GetTickCount() + gWINSQueryTimeout,
                             NetBTNodeStatusAnswerCallback, &queryData);
                        else
                            ret = NRC_SYSTEM;
                    }
                    else
                        ret = NRC_CMDCAN;
                }
                closesocket(fd);
            }
        }
        else
            ret = NRC_CMDTMO;
    }
    else if (ret == NRC_CMDCAN)
        ; /* do nothing, we were cancelled */
    else
        ret = NRC_CMDTMO;
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

static UCHAR NetBTAstat(void *adapt, PNCB ncb)
{
    NetBTAdapter *adapter = (NetBTAdapter *)adapt;
    UCHAR ret;

    TRACE("adapt %p, NCB %p\n", adapt, ncb);

    if (!adapter) return NRC_ENVNOTDEF;
    if (!ncb) return NRC_INVADDRESS;
    if (!ncb->ncb_buffer) return NRC_BADDR;
    if (ncb->ncb_length < sizeof(ADAPTER_STATUS)) return NRC_BUFLEN;

    if (ncb->ncb_callname[0] == '*')
    {
        DWORD physAddrLen;
        MIB_IFROW ifRow;
        PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer;
  
        memset(astat, 0, sizeof(ADAPTER_STATUS));
        astat->rev_major = 3;
        ifRow.dwIndex = adapter->ipr.dwIndex;
        if (GetIfEntry(&ifRow) != NO_ERROR)
            ret = NRC_BRIDGE;
        else
        {
            physAddrLen = min(ifRow.dwPhysAddrLen, 6);
            if (physAddrLen > 0)
                memcpy(astat->adapter_address, ifRow.bPhysAddr, physAddrLen);
            /* doubt anyone cares, but why not.. */
            if (ifRow.dwType == MIB_IF_TYPE_TOKENRING)
                astat->adapter_type = 0xff;
            else
                astat->adapter_type = 0xfe; /* for Ethernet */
            astat->max_sess_pkt_size = 0xffff;
            astat->xmit_success = adapter->xmit_success;
            astat->recv_success = adapter->recv_success;
        }
        ret = NRC_GOODRET;
    }
    else
        ret = NetBTAstatRemote(adapter, ncb);
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

static UCHAR NetBTFindName(void *adapt, PNCB ncb)
{
    NetBTAdapter *adapter = (NetBTAdapter *)adapt;
    UCHAR ret;
    const NBNameCacheEntry *cacheEntry = NULL;
    PFIND_NAME_HEADER foundName;

    TRACE("adapt %p, NCB %p\n", adapt, ncb);

    if (!adapter) return NRC_ENVNOTDEF;
    if (!ncb) return NRC_INVADDRESS;
    if (!ncb->ncb_buffer) return NRC_BADDR;
    if (ncb->ncb_length < sizeof(FIND_NAME_HEADER)) return NRC_BUFLEN;

    foundName = (PFIND_NAME_HEADER)ncb->ncb_buffer;
    memset(foundName, 0, sizeof(FIND_NAME_HEADER));

    ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
    if (ret == NRC_GOODRET)
    {
        if (cacheEntry)
        {
            DWORD spaceFor = min((ncb->ncb_length - sizeof(FIND_NAME_HEADER)) /
             sizeof(FIND_NAME_BUFFER), cacheEntry->numAddresses);
            DWORD ndx;

            for (ndx = 0; ndx < spaceFor; ndx++)
            {
                PFIND_NAME_BUFFER findNameBuffer;

                findNameBuffer =
                 (PFIND_NAME_BUFFER)((PUCHAR)foundName +
                 sizeof(FIND_NAME_HEADER) + foundName->node_count *
                 sizeof(FIND_NAME_BUFFER));
                memset(findNameBuffer->destination_addr, 0, 2);
                memcpy(findNameBuffer->destination_addr + 2,
                 &adapter->ipr.dwAddr, sizeof(DWORD));
                memset(findNameBuffer->source_addr, 0, 2);
                memcpy(findNameBuffer->source_addr + 2,
                 &cacheEntry->addresses[ndx], sizeof(DWORD));
                foundName->node_count++;
            }
            if (spaceFor < cacheEntry->numAddresses)
                ret = NRC_BUFLEN;
        }
        else
            ret = NRC_CMDTMO;
    }
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

static UCHAR NetBTSessionReq(SOCKET fd, const UCHAR *calledName,
 const UCHAR *callingName)
{
    UCHAR buffer[NBSS_HDRSIZE + MAX_DOMAIN_NAME_LEN * 2], ret;
    int r;
    unsigned int len = 0;
    DWORD bytesSent, bytesReceived, recvFlags = 0;
    WSABUF wsaBuf;

    buffer[0] = NBSS_REQ;
    buffer[1] = 0;

    len += NetBTNameEncode(calledName, &buffer[NBSS_HDRSIZE]);
    len += NetBTNameEncode(callingName, &buffer[NBSS_HDRSIZE + len]);

    NBR_ADDWORD(&buffer[2], len);

    wsaBuf.len = len + NBSS_HDRSIZE;
    wsaBuf.buf = (char*)buffer;

    r = WSASend(fd, &wsaBuf, 1, &bytesSent, 0, NULL, NULL);
    if(r < 0 || bytesSent < len + NBSS_HDRSIZE)
    {
        ERR("send failed\n");
        return NRC_SABORT;
    }

    /* I've already set the recv timeout on this socket (if it supports it), so
     * just block.  Hopefully we'll always receive the session acknowledgement
     * within one timeout.
     */
    wsaBuf.len = NBSS_HDRSIZE + 1;
    r = WSARecv(fd, &wsaBuf, 1, &bytesReceived, &recvFlags, NULL, NULL);
    if (r < 0 || bytesReceived < NBSS_HDRSIZE)
        ret = NRC_SABORT;
    else if (buffer[0] == NBSS_NACK)
    {
        if (r == NBSS_HDRSIZE + 1)
        {
            switch (buffer[NBSS_HDRSIZE])
            {
                case NBSS_ERR_INSUFFICIENT_RESOURCES:
                    ret = NRC_REMTFUL;
                    break;
                default:
                    ret = NRC_NOCALL;
            }
        }
        else
            ret = NRC_NOCALL;
    }
    else if (buffer[0] == NBSS_RETARGET)
    {
        FIXME("Got a session retarget, can't deal\n");
        ret = NRC_NOCALL;
    }
    else if (buffer[0] == NBSS_ACK)
        ret = NRC_GOODRET;
    else
        ret = NRC_SYSTEM;

    TRACE("returning 0x%02x\n", ret);
    return ret;
}

static UCHAR NetBTCall(void *adapt, PNCB ncb, void **sess)
{
    NetBTAdapter *adapter = (NetBTAdapter *)adapt;
    UCHAR ret;
    const NBNameCacheEntry *cacheEntry = NULL;

    TRACE("adapt %p, ncb %p\n", adapt, ncb);

    if (!adapter) return NRC_ENVNOTDEF;
    if (!ncb) return NRC_INVADDRESS;
    if (!sess) return NRC_BADDR;

    ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
    if (ret == NRC_GOODRET)
    {
        if (cacheEntry && cacheEntry->numAddresses > 0)
        {
            SOCKET fd;

            fd = WSASocketA(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
             WSA_FLAG_OVERLAPPED);
            if (fd != INVALID_SOCKET)
            {
                DWORD timeout;
                struct sockaddr_in sin;

                if (ncb->ncb_rto > 0)
                {
                    timeout = ncb->ncb_rto * 500;
                    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
                     sizeof(timeout));
                }
                if (ncb->ncb_rto > 0)
                {
                    timeout = ncb->ncb_sto * 500;
                    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
                     sizeof(timeout));
                }

                memset(&sin, 0, sizeof(sin));
                memcpy(&sin.sin_addr, &cacheEntry->addresses[0],
                 sizeof(sin.sin_addr));
                sin.sin_family = AF_INET;
                sin.sin_port   = htons(PORT_NBSS);
                /* FIXME: use nonblocking mode for the socket, check the
                 * cancel flag periodically
                 */
                if (connect(fd, (struct sockaddr *)&sin, sizeof(sin))
                 == SOCKET_ERROR)
                    ret = NRC_CMDTMO;
                else
                {
                    static const UCHAR fakedCalledName[] = "*SMBSERVER";
                    const UCHAR *calledParty = cacheEntry->nbname[0] == '*'
                     ? fakedCalledName : cacheEntry->nbname;

                    ret = NetBTSessionReq(fd, calledParty, ncb->ncb_name);
                    if (ret != NRC_GOODRET && calledParty[0] == '*')
                    {
                        FIXME("NBT session to \"*SMBSERVER\" refused,\n");
                        FIXME("should try finding name using ASTAT\n");
                    }
                }
                if (ret != NRC_GOODRET)
                    closesocket(fd);
                else
                {
                    NetBTSession *session = HeapAlloc(
                     GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NetBTSession));

                    if (session)
                    {
                        session->fd = fd;
                        InitializeCriticalSection(&session->cs);
                        session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NetBTSession.cs");
                        *sess = session;
                    }
                    else
                    {
                        ret = NRC_OSRESNOTAV;
                        closesocket(fd);
                    }
                }
            }
            else
                ret = NRC_OSRESNOTAV;
        }
        else
            ret = NRC_NAMERR;
    }
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

/* Notice that I don't protect against multiple thread access to NetBTSend.
 * This is because I don't update any data in the adapter, and I only make a
 * single call to WSASend, which I assume to act atomically (not interleaving
 * data from other threads).
 * I don't lock, because I only depend on the fd being valid, and this won't be
 * true until a session setup is completed.
 */
static UCHAR NetBTSend(void *adapt, void *sess, PNCB ncb)
{
    NetBTAdapter *adapter = (NetBTAdapter *)adapt;
    NetBTSession *session = (NetBTSession *)sess;
    UCHAR buffer[NBSS_HDRSIZE], ret;
    int r;
    WSABUF wsaBufs[2];
    DWORD bytesSent;

    TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb);

    if (!adapter) return NRC_ENVNOTDEF;
    if (!ncb) return NRC_INVADDRESS;
    if (!ncb->ncb_buffer) return NRC_BADDR;
    if (!session) return NRC_SNUMOUT;
    if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT;

    buffer[0] = NBSS_MSG;
    buffer[1] = 0;
    NBR_ADDWORD(&buffer[2], ncb->ncb_length);

    wsaBufs[0].len = NBSS_HDRSIZE;
    wsaBufs[0].buf = (char*)buffer;
    wsaBufs[1].len = ncb->ncb_length;
    wsaBufs[1].buf = (char*)ncb->ncb_buffer;

    r = WSASend(session->fd, wsaBufs, sizeof(wsaBufs) / sizeof(wsaBufs[0]),
     &bytesSent, 0, NULL, NULL);
    if (r == SOCKET_ERROR)
    {
        NetBIOSHangupSession(ncb);
        ret = NRC_SABORT;
    }
    else if (bytesSent < NBSS_HDRSIZE + ncb->ncb_length)
    {
        FIXME("Only sent %d bytes (of %d), hanging up session\n", bytesSent,
         NBSS_HDRSIZE + ncb->ncb_length);
        NetBIOSHangupSession(ncb);
        ret = NRC_SABORT;
    }
    else
    {
        ret = NRC_GOODRET;
        adapter->xmit_success++;
    }
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

static UCHAR NetBTRecv(void *adapt, void *sess, PNCB ncb)
{
    NetBTAdapter *adapter = (NetBTAdapter *)adapt;
    NetBTSession *session = (NetBTSession *)sess;
    UCHAR buffer[NBSS_HDRSIZE], ret;
    int r;
    WSABUF wsaBufs[2];
    DWORD bufferCount, bytesReceived, flags;

    TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb);

    if (!adapter) return NRC_ENVNOTDEF;
    if (!ncb) return NRC_BADDR;
    if (!ncb->ncb_buffer) return NRC_BADDR;
    if (!session) return NRC_SNUMOUT;
    if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT;

    EnterCriticalSection(&session->cs);
    bufferCount = 0;
    if (session->bytesPending == 0)
    {
        bufferCount++;
        wsaBufs[0].len = NBSS_HDRSIZE;
        wsaBufs[0].buf = (char*)buffer;
    }
    wsaBufs[bufferCount].len = ncb->ncb_length;
    wsaBufs[bufferCount].buf = (char*)ncb->ncb_buffer;
    bufferCount++;

    flags = 0;
    /* FIXME: should poll a bit so I can check the cancel flag */
    r = WSARecv(session->fd, wsaBufs, bufferCount, &bytesReceived, &flags,
     NULL, NULL);
    if (r == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
    {
        LeaveCriticalSection(&session->cs);
        ERR("Receive error, WSAGetLastError() returns %d\n", WSAGetLastError());
        NetBIOSHangupSession(ncb);
        ret = NRC_SABORT;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -