< NetBIOS | Winsock2 Supported Protocols Main | NetBIOS Server Examples >


 

 

Winsock 2: Other Supported Protocols 4 Part 4

 

 

What do we have in this chapter 4 part 4?

  1. Another Day Another NetBIOS Example

 

Another Day Another NetBIOS Example

 

Create a new empty Win32 console mode application and add the project/solution name.

 

Another Netbios program example - Creating a new empty Win32 console mode application and add the project/solution name.

 

Add the following source code.

 

// Description:

//    This sample illustrates how to perform a NetBIOS adapter

//    status either as a local or remote call. Depending on how

//    you call the utility will determine what kind of information

//    is returned.  A local call returns only those names in the

//    current process' name table. A remote call will return all

//    names registered on the machine.

//

// Command Line Options:

//    Netbiosstatus [-l][-r]

//    NONE       Just perform a local status which will return

//               only those names added by this process.

//    -l:NAME    NetBIOS name to add to the local NetBIOS

//               name table to make the call "remotely" on the

//               local machine.

//    -r:NAME    NetBIOS name of the remote machine to query

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include "nbcommon.h"

 

#define MAX_SESSIONS   254

#define MAX_NAMES         254

 

BOOL    bLocalName=FALSE,                    // Are we adding a local name

                bRemoteName=FALSE;               // Are we doing a remote status?

char    szLocalName[NCBNAMSZ+1],         // Local NetBIOS name

            szRemoteName[NCBNAMSZ+1];    // Remote NetBIOS name

 

// We're safe in hardcoding the number of NAME_BUFFER

// messages since the maximum number of names possible on a single LANA is 254

typedef struct {

    ADAPTER_STATUS  adapter;

    NAME_BUFFER     names[254];

} MESSAGE_BUFFER;

 

// Function: ValidateArgs

// Description: Check for various command line options.

int ValidateArgs(int argc, char **argv)

{

    int    i;

 

    for(i=1; i < argc ;i++)

    {

        if ((argv[i][0] == '-') || (argv[i][0] == '/'))

        {

            switch (tolower(argv[i][1]))

            {

                case 'l':

                    // fake the status call on this machine to make

                    // it look like it was a remote call

                    bLocalName = TRUE;

                    strncpy_s(szLocalName, sizeof(szLocalName),&argv[i][3], NCBNAMSZ);

                    szLocalName[NCBNAMSZ] = 0;

                    break;

                case 'r':       // do an adapter status on another machine

                    bRemoteName = TRUE;

                    strncpy_s(szRemoteName, sizeof(szRemoteName),&argv[i][3], NCBNAMSZ);

                    szRemoteName[NCBNAMSZ] = 0;

                    break;

                default:

                    printf("Usage: Netbiosstatus [/r:LocalName] [/l:LocalName]\n");

                    break;

             }

        }

    }

    return 0;

}

 

// Function: PrintAdapterInfo

// Description:

//    This function prints out the adapter info. About the only useful

//    information returned in this structure is:  MAC address, max

//    datagram size, and max number of sessions. More often that not

//    the other fields are not set (i.e. there always zero)

void PrintAdapterInfo(int lana, ADAPTER_STATUS adapter)

{

        printf("                      LANA: %d\n", lana);

        printf("               MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",

        adapter.adapter_address[0], adapter.adapter_address[1],

        adapter.adapter_address[2], adapter.adapter_address[3],

        adapter.adapter_address[4], adapter.adapter_address[5]);

 

    // Print the version of the NetBIOS specification implemented.

    // This should be 3.0 for current Microsoft Win332 platforms.

    printf("           Netbios Version: %d.%d\n", adapter.rev_major,adapter.rev_minor);

 

     // Print the type of network adapter

    printf("              Adapter Type: ");

    if (adapter.adapter_type == 0xFF)

           printf("Token Ring\n");

    else if (adapter.adapter_type == 0xFE)

           printf("Ethernet\n");

    else

           printf("Unknown\n");

 

    printf("                  Duration: %d minutes\n", adapter.duration);

    printf("  Num Aborted Trasmissions: %d\n", adapter.xmit_aborts);

    printf("   Num Transmitted Packets: %d\n", adapter.xmit_success);

    printf("      Num Received Packets: %d\n", adapter.recv_success);

    printf("             Num Free NCBs: %d\n", adapter.free_ncbs);

    printf("         Max Datagram Size: %d\n", adapter.max_dgram_size);

    printf("   Number Pending Sessions: %d\n", adapter.pending_sess);

    printf("    Max Number of Sessions: %d\n", adapter.max_cfg_sess);

    printf("Max Size of Session Packet: %d\n", adapter.max_sess_pkt_size);

}

 

// Function: PrintNameInfo

// Description: Prints out a NetBIOS name and its related information

void PrintNameInfo(NAME_BUFFER *names, int namecount)

{

            char namebuff[NCBNAMSZ + 1];

            int i;

 

            if (namecount == 0)

            {

                printf("No names in local name table\n\n\n");

                    return;

            }

 

    printf("\nName             Type  Number  Flags\n");

 

    for(i=0; i < namecount ;i++)

    {

        FormatNetbiosName((char *)names[i].name, namebuff);

        printf("%s <%02x>     %-2d   ", namebuff, names[i].name[NCBNAMSZ-1], names[i].name_num);

 

        if (names[i].name_flags & REGISTERING)

            printf("Registering  ");

        else if (names[i].name_flags & REGISTERED)

            printf("Registered ");

        else if (names[i].name_flags & DEREGISTERED)

            printf("Deregistered ");

        else if (names[i].name_flags & DUPLICATE)

            printf("Duplicate ");

        else if (names[i].name_flags & DUPLICATE_DEREG)

            printf("Duplicate-Deregistered ");

        if (names[i].name_flags & GROUP_NAME)

            printf("Group-Name ");

        printf("\n");

    }

    printf("\n\n");

}

 

 

 

 

// Function: LanaStatus

// Description: Perform a LAN adapter status command.

int LanaStatus(int lana, char *name)

{

    // http://msdn.microsoft.com/en-us/library/bb870902(VS.85).aspx

    NCB ncb;

    MESSAGE_BUFFER  mb;

 

    ZeroMemory(&mb,  sizeof(MESSAGE_BUFFER));

    ZeroMemory(&ncb,  sizeof(NCB));

 

    memset(ncb.ncb_callname, ' ', NCBNAMSZ);

 

    // Check command line options to see if the call is

    // made locally or remotely.

    if ((bLocalName == FALSE) && (bRemoteName == FALSE))

        ncb.ncb_callname[0] = '*';

    else

        strncpy_s((char *)ncb.ncb_callname, sizeof(ncb.ncb_callname), name, strlen(name));

 

            // May need to repeat for several times to avoid timeout! (NRC_CMDTMO == 0x05)

            ncb.ncb_command = NCBASTAT;

            ncb.ncb_buffer  = (UCHAR *)&mb;

            ncb.ncb_length  = sizeof(MESSAGE_BUFFER);

            ncb.ncb_lana_num= lana;

 

    if (Netbios(&ncb) != NRC_GOODRET)

    {

        printf("Netbios(): NCBASTAT failed with returned code %d\n", ncb.ncb_retcode);

        return ncb.ncb_retcode;

    }

    PrintAdapterInfo(lana, mb.adapter);

    PrintNameInfo(mb.names, mb.adapter.name_count);

 

    return NRC_GOODRET;

}

 

// Function: main

// Description:

//    Setup the NetBIOS interface, parse the arguments, and call the

//    adapter status command either locally or remotely depending on

//    the user supplied arguments.

int main(int argc, char **argv)

{

    LANA_ENUM   lenum;

    int    i, num;

 

    if(argc<2)

    {

         printf("Usage: %s [/l:LOCALNAME | /r:REMOTENAME]\n", argv[0]);

         printf("Example: %s /l:gedik\n", argv[0]);

         printf("Example: %s /r:tergedik\n", argv[0]);

         exit(1);

     }

 

    ValidateArgs(argc, argv);

 

    // Make sure both command line flags weren't set

    if (bLocalName && bRemoteName)

    {

        // Should put in one function lor!

        printf("Usage: %s [/l:LOCALNAME | /r:REMOTENAME]\n", argv[0]);

        printf("Example: %s /l:gedik\n", argv[0]);

        printf("Example: %s /r:tergedik\n", argv[0]);

        return 1;

    }

 

    // Enumerate all LANAs and reset each one

    if (LanaEnum(&lenum) != NRC_GOODRET)

        return 1;

    if (ResetAll(&lenum, (UCHAR)MAX_SESSIONS, (UCHAR)MAX_NAMES, FALSE) != NRC_GOODRET)

    return 1;

 

    // If we're called with a local name we need to add it to the name table.

    if (bRemoteName == FALSE)

    {

        for(i=0; i < lenum.length ;i++)

        {

            if (bLocalName)

                AddName(lenum.lana[i], szLocalName, &num);

            LanaStatus(lenum.lana[i], szLocalName);

        }

    }

    else

    {

        for(i=0; i < lenum.length ;i++)

            LanaStatus(lenum.lana[i], szRemoteName);

    }

    return 0;

}

 

Next, add the nbcommon.h header file.

 

Another Netbios program example - Adding the nbcommon.h header file

 

Add the following source code.

 

//         This header file contains the function prototypes for a set

//         of functions that implement some of the most common NetBIOS

//         functions such as enumerating LANAs, adding names, removing

//         names, etc. The functions are implemented in nbcommon.cpp

#include   <windows.h>

// Don't forget to link to Netapi32.lib

#include   <nb30.h>

 

int   Recv(int lana,int lsn, char *buffer, DWORD *len);

int   Send(int lana, int lsn, char *data, DWORD len);

int   AddName(int lana,char *name, int *num);

int   DelName(int lana, char *name);

int   AddGroupName(int lana, char *name,int *num);

int   ResetAll(LANA_ENUM *lenum, UCHAR ucMaxSession,UCHAR ucMaxName,BOOL bFirstName);

int   LanaEnum(LANA_ENUM *lenum);

int   Hangup(int lana, int lsn);

int   Cancel(PNCB pncb);

int   FormatNetbiosName(char *nbname, char *outname);

 

Then, add the definition file for nbcommon.h, nbcommon.cpp.

 

-------------------------------------------------------

Another Netbios program example - Adding the nbcommon.cpp definition file

 

Add the following source code.

 

// Description:

//    This file contains the function bodies for a set of

//    common NetBIOS functions.  See the descriptions for

//    each function on what each one does. These functions

//    are used by the other NetBIOS sample programs so this

//    file needs to be compiled to object code and linked

//    with the other executable programs.

//

// Command Line Options:

//    NONE - Compile to object code

//

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include "nbcommon.h"

 

// Enumerate all LANA numbers

int LanaEnum(LANA_ENUM *lenum)

{

    NCB ncb;

   

    ZeroMemory(&ncb, sizeof(NCB));

    ncb.ncb_command = NCBENUM;

    ncb.ncb_buffer = (PUCHAR)lenum;

    ncb.ncb_length = sizeof(LANA_ENUM);

 

    if (Netbios(&ncb) != NRC_GOODRET)

    {

         printf("ERROR: Netbios: NCBENUM: %d\n", ncb.ncb_retcode);

         return ncb.ncb_retcode;

    }

    return NRC_GOODRET;

}

 

// Reset each LANA listed in the LANA_ENUM structure. Also, set

// the NetBIOS environment (max sessions, max name table size),

// and use the first NetBIOS name

int ResetAll(LANA_ENUM *lenum, UCHAR ucMaxSession,UCHAR ucMaxName, BOOL bFirstName)  

{

            NCB ncb;

            int i;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBRESET;

            ncb.ncb_callname[0] = ucMaxSession;

            ncb.ncb_callname[2] = ucMaxName;

            ncb.ncb_callname[3] = (UCHAR)bFirstName;

 

            for(i = 0; i < lenum->length; i++)

            {

                        ncb.ncb_lana_num = lenum->lana[i];

                        if (Netbios(&ncb) != NRC_GOODRET)

                        {

                                    printf("ERROR: Netbios: NCBRESET[%d]: %d\n",ncb.ncb_lana_num, ncb.ncb_retcode);

                                    return ncb.ncb_retcode;

                        }

            }

            return NRC_GOODRET;

}

 

// Add the given name to the given LANA number. Return the name

// number for the registered name

int AddName(int lana, char *name, int *num)

{

            NCB ncb;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBADDNAME;

            ncb.ncb_lana_num = lana;

            memset(ncb.ncb_name, ' ', NCBNAMSZ);

 

            strncpy_s((char *)ncb.ncb_name, sizeof(ncb.ncb_name),name, strlen(name));

            if (Netbios(&ncb) != NRC_GOODRET)

            {

                        printf("ERROR: Netbios: NCBADDNAME[lana=%d;name=%s]: %d\n", lana, name, ncb.ncb_retcode);

                        return ncb.ncb_retcode;

            }

            *num = ncb.ncb_num;

            return NRC_GOODRET;

}

 

// Add the given NetBIOS group name to the given LANA

// number. Return the name number for the added name

int AddGroupName(int lana, char *name, int *num)

{

            NCB ncb;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBADDGRNAME;

            ncb.ncb_lana_num = lana;

            memset(ncb.ncb_name, ' ', NCBNAMSZ);

 

            strncpy_s((char *)ncb.ncb_name, sizeof(ncb.ncb_name),name, strlen(name));

 

            if (Netbios(&ncb) != NRC_GOODRET)

            {

                        printf("ERROR: Netbios: NCBADDGRNAME[lana=%d;name=%s]: %d\n", lana, name, ncb.ncb_retcode);

                        return ncb.ncb_retcode;

            }

            *num = ncb.ncb_num;

            return NRC_GOODRET;

}

 

// Delete the given NetBIOS name from the name table associated

// with the LANA number 

int DelName(int lana, char *name)

{

             NCB ncb;

 

             ZeroMemory(&ncb, sizeof(NCB));

             ncb.ncb_command = NCBDELNAME;

             ncb.ncb_lana_num = lana;

             memset(ncb.ncb_name, ' ', NCBNAMSZ);

 

             strncpy_s((char *)ncb.ncb_name, sizeof(ncb.ncb_name),name, strlen(name));

 

             if (Netbios(&ncb) != NRC_GOODRET)

             {

                         printf("ERROR: Netbios: NCBADDNAME[lana=%d;name=%s]: %d\n",lana, name, ncb.ncb_retcode);

                         return ncb.ncb_retcode;

             }

             return NRC_GOODRET;

}

 

// Send len bytes from the data buffer on the given session (lsn) and lana number

int Send(int lana, int lsn, char *data, DWORD len)

{

            NCB ncb;

            int retcode;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBSEND;

            ncb.ncb_buffer = (PUCHAR)data;

            ncb.ncb_length = (WORD)len;

            ncb.ncb_lana_num = lana;

            ncb.ncb_lsn = lsn;

            retcode = Netbios(&ncb);

            return retcode;

 

// Receive up to len bytes into the data buffer on the given session

// (lsn) and lana number.

int Recv(int lana, int lsn, char *buffer, DWORD *len)

{

            NCB ncb;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBRECV;

            ncb.ncb_buffer = (PUCHAR)buffer;

            ncb.ncb_length = (WORD)*len;

            ncb.ncb_lana_num = lana;

            ncb.ncb_lsn = lsn;

 

            if (Netbios(&ncb) != NRC_GOODRET)

            {

                        *len = -1;

                        return ncb.ncb_retcode;

            }

            *len = ncb.ncb_length;

            return NRC_GOODRET;

}

 

// Disconnect the given session on the given lana number

int Hangup(int lana, int lsn)

{

            NCB ncb;

            int retcode;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBHANGUP;

            ncb.ncb_lsn = lsn;

            ncb.ncb_lana_num = lana;

            retcode = Netbios(&ncb);

            return retcode;

}

 

// Cancel the given asynchronous command denoted in the NCB

// structure parameter

int Cancel(PNCB pncb)

{

            NCB ncb;

 

            ZeroMemory(&ncb, sizeof(NCB));

            ncb.ncb_command = NCBCANCEL;

            ncb.ncb_buffer = (PUCHAR)pncb;

            ncb.ncb_lana_num = pncb->ncb_lana_num;

 

    if (Netbios(&ncb) != NRC_GOODRET)

    {

          printf("ERROR: NetBIOS: NCBCANCEL: %d\n", ncb.ncb_retcode);

          return ncb.ncb_retcode;

     }

     return NRC_GOODRET;

}

 

// Format the given NetBIOS name so that it is printable. Any

// unprintable characters are replaced by a period. The outname

// buffer is the returned string, which is assumed to be at least

// NCBNAMSZ + 1 characters in length

int FormatNetbiosName(char *nbname, char *outname)

{

            int i;

 

            strncpy_s(outname, 17,nbname, NCBNAMSZ);

            outname[NCBNAMSZ - 1] = '\0';

            for(i = 0; i < NCBNAMSZ - 1; i++)

            {

                        // If the character isn't printable replace it with a '.'

                        if (!((outname[i] >= 32) && (outname[i] <= 126)))

                                    outname[i] = '.';

            }

            return NRC_GOODRET;

}

 

 

 

 

Don’t forget to link to the project to Netapi32.lib (for nb30.h). Then, build and run the program.

 

Another Netbios program example - A sample output with an argument

 

The NCBSTAT suffer a time out for this program.

 

Another Netbios program example - Another sample output with an argument

 

Microsoft documentation said that:

 

"The IBM NetBIOS 3.0 specification supports only two LANA numbers, because NetBEUI was originally the only protocol that supported NetBIOS, and a computer could contain only two network adapters at that time. Specifying LANA 0 directed a command to the first adapter, and specifying LANA 1 directed a command to the second adapter. Because many computers had only one network adapter, many MS-DOS based applications sent all their requests to LANA 0. If a second network adapter was installed, some applications allowed the user to specify the use of LANA 1 instead. As a result, LANA 0 became the default setting, though it was never intended as such."

 

Well, great product with great 'bugs'. To overcome the command time out, specify the LANA number in the ncb_lana_num member of the NCB structure directly when you issue a NetBIOS command instead of letting the command do the searching and this issue is obvious in multihomed system.

 

 


< NetBIOS | Winsock2 Supported Protocols Main | NetBIOS Server Examples >