Datagram

This application demonstrates the various datagram operations possible from NetBIOS. This includes sending and eceiving both directed and group datagrams as well as broadcast datagrams.
Compile
cl -o Nbdgram.exe Nbdgram.c ..\Common\Nbcommon.obj Netapi32.lib User32.lib
Command Line Options
nbdgram.exe options

  1. -n:NAME Register my unique name NAME
  2. -g:NAME Register my group name NAME
  3. -s I will be sending datagrams
  4. -c:xxx Number of datagrams to send
  5. -r:NAME The recipients NetBIOS name
  6. -b Use broadcast datagrams
  7. -a Receive datagrams for any NetBIOS name
  8. -l:xxx Send datagrams on LANA number xxx only
  9. -d:xxx Delay (in milliseconds) between sends
// Module Name: Nbdgram.c
//
// Description:
//    This application demonstrates the various datagram operations
//    possible from NetBIOS.  This includes sending and receiving
//    both directed and group datagrams as well as broadcast datagrams.
//
// Compile:
//    cl -o Nbdgram.exe Nbdgram.c ..\Common\Nbcommon.obj
//      Netapi32.lib User32.lib
//
// Command Line Options:
//    nbdgram.exe options
//    -n:NAME    Register my unique name NAME
//    -g:NAME    Register my group name NAME
//    -s         I will be sending datagrams
//    -c:xxx     Number of datagrams to send
//    -r:NAME    The recipients NetBIOS name
//    -b         Use broadcast datagrams
//    -a         Receive datagrams for any NetBIOS name
//    -l:xxx     Send datagrams on LANA number xxx only
//    -d:xxx     Delay (in milliseconds) between sends
//    
#include 
#include 
#include 

#include "..\Common\nbcommon.h"

#define MAX_SESSIONS            254
#define MAX_NAMES               254
#define MAX_DATAGRAM_SIZE       512

BOOL   bSender = FALSE,               // Send or receive datagrams
       bRecvAny = FALSE,              // Receive for any name
       bUniqueName = TRUE,            // Register my name as unique?
       bBroadcast = FALSE,            // Use broadcast datagrams?
       bOneLana = FALSE;              // Use all LANAs or just one?
char   szLocalName[NCBNAMSZ + 1],     // Local NetBIOS name
       szRecipientName[NCBNAMSZ + 1]; // Recipients NetBIOS name
DWORD  dwNumDatagrams = 25,           // Number of datagrams to sen
       dwOneLana,                     // If using one LANA, which one
       dwDelay = 0;                   // Delay between datagram send

//
// Function: ValidateArgs
//
// Description:
//    This function parses the command line arguments
//    and sets various global flags indicating the selections.
//
void ValidateArgs(int argc, char **argv)
{
    int                i;

    for(i = 1; i < argc; i++)
    {
        if (strlen(argv[i]) < 2)
            continue;
        if ((argv[i][0] == '-') || (argv[i][0] == '/'))
        {
            switch (tolower(argv[i][1]))
            {
                case 'n':        // Use a unique name
                    bUniqueName = TRUE;
                    if (strlen(argv[i]) > 2)
                        strcpy(szLocalName, &argv[i][3]);
                    break;
                case 'g':        // Use a group name
                    bUniqueName = FALSE;
                    if (strlen(argv[i]) > 2)
                        strcpy(szLocalName, &argv[i][3]);
                    break;
                case 's':        // Send datagrams
                    bSender = TRUE;
                    break;
                case 'c':        // Num datagrams to send or receive
                    if (strlen(argv[i]) > 2)
                        dwNumDatagrams = atoi(&argv[i][3]);
                    break;
                case 'r':        // Recipient's name for datagrams
                    if (strlen(argv[i]) > 2)
                        strcpy(szRecipientName, &argv[i][3]);
                    break;
                case 'b':        // Use broadcast datagrams
                    bBroadcast = TRUE;
                    break;
                case 'a':        // Receive datagrams on any name
                    bRecvAny = TRUE;
                    break;
                case 'l':        // Operate on this LANA only
                    bOneLana = TRUE;
                    if (strlen(argv[i]) > 2)
                        dwOneLana = atoi(&argv[i][3]);
                    break;
                case 'd':        // Delay (millisecs) between sends
                    if (strlen(argv[i]) > 2)
                        dwDelay = atoi(&argv[i][3]);
                    break;
                default:
                    printf("usage: nbdgram ?\n");
                    break;

             }
        }
    }
    return;
}

//
// Function: DatagramSend
//
// Description:
//    Send a directed datagram to the specified recipient on the 
//    specified LANA number from the given name number to the
//    specified recipient. Also specified is the data buffer and 
//    the number of bytes to send.
//
int DatagramSend(int lana, int num, char *recipient, 
				 char *buffer, int buflen)
{
    NCB                ncb;

    ZeroMemory(&ncb, sizeof(NCB));
    ncb.ncb_command = NCBDGSEND;
    ncb.ncb_lana_num = lana;
    ncb.ncb_num = num;
    ncb.ncb_buffer = (PUCHAR)buffer;
    ncb.ncb_length = buflen;

    memset(ncb.ncb_callname, ' ', NCBNAMSZ);
    strncpy(ncb.ncb_callname, recipient, strlen(recipient));

    if (Netbios(&ncb) != NRC_GOODRET)
    {
        printf("Netbios: NCBDGSEND failed: %d\n", ncb.ncb_retcode);
        return ncb.ncb_retcode;
    }
    return NRC_GOODRET;
}

//
// Function: DatagramSendBC
//
// Description:
//    Send a broadcast datagram on the specified LANA number from the 
//    given name number.  Also specified is the data buffer and number
//    of bytes to send.
//
int DatagramSendBC(int lana, int num, char *buffer, int buflen)
{
    NCB                ncb;

    ZeroMemory(&ncb, sizeof(NCB));
    ncb.ncb_command = NCBDGSENDBC;
    ncb.ncb_lana_num = lana;
    ncb.ncb_num = num;
    ncb.ncb_buffer = (PUCHAR)buffer;
    ncb.ncb_length = buflen;

    if (Netbios(&ncb) != NRC_GOODRET)
    {
        printf("Netbios: NCBDGSENDBC failed: %d\n", ncb.ncb_retcode);
        return ncb.ncb_retcode;
    }
    return NRC_GOODRET;
}

//
// Function: DatagramRecv
//
// Description:
//    Receive a datagram on the given LANA number directed towards the
//    name represented by num.  Data is copied into the supplied buffer.
//    If hEvent is not zero then the receive call is made asynchronously
//    with the supplied event handle. If num is 0xFF then listen for a
//    datagram destined for any NetBIOS name registered by the process.
//
int DatagramRecv(PNCB pncb, int lana, int num, char *buffer, 
                 int buflen, HANDLE hEvent)
{
    ZeroMemory(pncb, sizeof(NCB));
    if (hEvent)
    {
        pncb->ncb_command = NCBDGRECV | ASYNCH;
        pncb->ncb_event = hEvent;
    }
    else
        pncb->ncb_command = NCBDGRECV;
    pncb->ncb_lana_num = lana;
    pncb->ncb_num = num;
    pncb->ncb_buffer = (PUCHAR)buffer;
    pncb->ncb_length = buflen;

    if (Netbios(pncb) != NRC_GOODRET)
    {
        printf("Netbos: NCBDGRECV failed: %d\n", pncb->ncb_retcode);
        return pncb->ncb_retcode;
    }
    return NRC_GOODRET;
}

//
// Function: DatagramRecvBC
//
// Description:
//    Receive a broadcast datagram on the given LANA number.
//    Data is copied into the supplied buffer.  If hEvent is not zero 
//    then the receive call is made asynchronously with the supplied 
//    event handle.
//
int DatagramRecvBC(PNCB pncb, int lana, int num, char *buffer, 
                   int buflen, HANDLE hEvent)
{
    ZeroMemory(pncb, sizeof(NCB));
    if (hEvent)
    {
        pncb->ncb_command = NCBDGRECVBC | ASYNCH;
        pncb->ncb_event = hEvent;
    }
    else
        pncb->ncb_command = NCBDGRECVBC;
    pncb->ncb_lana_num = lana;
    pncb->ncb_num = num;
    pncb->ncb_buffer = (PUCHAR)buffer;
    pncb->ncb_length = buflen;
  
    if (Netbios(pncb) != NRC_GOODRET)   
    {
        printf("Netbios: NCBDGRECVBC failed: %d\n", pncb->ncb_retcode);
        return pncb->ncb_retcode;
    }
    return NRC_GOODRET;
}

//
// Function: main
//
// Description:
//    Initialize the NetBIOS interface, allocate resources, and then
//    send or receive datagrams according to the user's options.
//
int main(int argc, char **argv)
{
    LANA_ENUM   lenum;
    int         i, j;
    char        szMessage[MAX_DATAGRAM_SIZE],
                szSender[NCBNAMSZ + 1];
    DWORD      *dwNum = NULL,
                dwBytesRead,
                dwErr;

    ValidateArgs(argc, argv);
    //
    // Enumerate and reset the LANA numbers
    //
    if ((dwErr = LanaEnum(&lenum)) != NRC_GOODRET)
    {
        printf("LanaEnum failed: %d\n", dwErr);
        return 1;
    }
    if ((dwErr = ResetAll(&lenum, (UCHAR)MAX_SESSIONS,
		(UCHAR)MAX_NAMES, FALSE)) != NRC_GOODRET)
    {
        printf("ResetAll failed: %d\n", dwErr);
        return 1;
    }
    //
    // This buffer holds the name number for the NetBIOS name added
    // to each LANA
    //
    dwNum = (DWORD *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
            sizeof(DWORD) * lenum.length);
    if (dwNum == NULL)
    {
        printf("out of memory\n");
        return 1;
    }
    //
    // If we're going to operate only on one LANA register the name
    // only on that specified LANA; otherwise register it on all.
    // 
    if (bOneLana)
    {
        if (bUniqueName)
            AddName(dwOneLana, szLocalName, &dwNum[0]);
        else
            AddGroupName(dwOneLana, szLocalName, &dwNum[0]);
    }
    else
    {
        for(i = 0; i < lenum.length; i++)
        {
            if (bUniqueName)
                AddName(lenum.lana[i], szLocalName, &dwNum[i]);
            else
                AddGroupName(lenum.lana[i], szLocalName, &dwNum[i]);
        }
    }
    // We are sending datagrams
    //
    if (bSender)
    {
        // Broadcast sender
        //
        if (bBroadcast)
        {
            if (bOneLana)
            {
                // Broadcast the message on the one LANA only
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    wsprintf(szMessage,
						"[%03d] Test broadcast datagram", j);
                    if (DatagramSendBC(dwOneLana, dwNum[0],
						szMessage, strlen(szMessage))
						!= NRC_GOODRET)
                        return 1;
                    Sleep(dwDelay);
                }
            }
            else
            {
                // Broadcast the message on every LANA on the local 
                // machine
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    for(i = 0; i < lenum.length; i++)
                    {
                        wsprintf(szMessage,
							"[%03d] Test broadcast datagram", j);
                        if (DatagramSendBC(lenum.lana[i], dwNum[i],
							szMessage, strlen(szMessage)) 
							!= NRC_GOODRET)
                            return 1;
                    }
                    Sleep(dwDelay);
                }
            }
        }
        else
        {
            if (bOneLana)
            {
                // Send a directed message to the one LANA specified
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    wsprintf(szMessage,
						"[%03d] Test directed datagram", j);
                    if (DatagramSend(dwOneLana, dwNum[0],
						szRecipientName, szMessage,
						strlen(szMessage)) != NRC_GOODRET)
                        return 1;
                    Sleep(dwDelay);
                }
            }
            else
            {
                // Send a directed message to the each LANA on the 
                // local machine
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    for(i = 0; i < lenum.length; i++)
                    {
                        wsprintf(szMessage,
							"[%03d] Test directed datagram", j);
						printf("count: %d.%d\n", j,i);
                        if (DatagramSend(lenum.lana[i], dwNum[i], 
                            szRecipientName, szMessage, 
                            strlen(szMessage)) != NRC_GOODRET)
                            return 1;
                    }
                    Sleep(dwDelay);
                }
            }
        }
    }
    else                // We are receiving datagrams
    {
        NCB     *ncb=NULL;
        char    **szMessageArray = NULL;
        HANDLE  *hEvent=NULL;
        DWORD   dwRet;

        // Allocate an array of NCB structure to submit to each recv 
        // on each LANA
        //
        ncb = (NCB *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                    sizeof(NCB) * lenum.length);
        //
        // Allocate an array of incoming data buffers
        //
        szMessageArray = (char **)GlobalAlloc(GMEM_FIXED, 
                sizeof(char *) * lenum.length);
        for(i = 0; i < lenum.length; i++)
            szMessageArray[i] = (char *)GlobalAlloc(GMEM_FIXED, 
                    MAX_DATAGRAM_SIZE);
        //
        // Allocate an array of event handles for 
		// asynchronous receives
        //
        hEvent = (HANDLE *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 
                sizeof(HANDLE) * lenum.length);
        for(i = 0; i < lenum.length; i++)
            hEvent[i] = CreateEvent(0, TRUE, FALSE, 0);

        if (bBroadcast)
        {
            if (bOneLana)
            {
                // Post synchronous broadcast receives on 
				// the one LANA specified
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    if (DatagramRecvBC(&ncb[0], dwOneLana, dwNum[0], 
                        szMessageArray[0], MAX_DATAGRAM_SIZE,  
                        NULL) != NRC_GOODRET)
                        return 1;
                    FormatNetbiosName(ncb[0].ncb_callname, szSender);
                    printf("%03d [LANA %d] Message: '%s' "
						"received from: %s\n", j,
						ncb[0].ncb_lana_num, szMessageArray[0],
                        szSender);
                }
            }
            else
            {
                // Post asynchronous broadcast receives on each LANA 
                // number available. For each command that succeeded 
                // print the message otherwise cancel the command.
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    for(i = 0; i < lenum.length; i++)
                    {
                        dwBytesRead = MAX_DATAGRAM_SIZE;
                        if (DatagramRecvBC(&ncb[i], lenum.lana[i],
							dwNum[i], szMessageArray[i],
							MAX_DATAGRAM_SIZE, hEvent[i])
							!= NRC_GOODRET)
                            return 1;
                    }
                    dwRet = WaitForMultipleObjects(lenum.length, 
                        hEvent, FALSE, INFINITE);
                    if (dwRet == WAIT_FAILED)
                    {
                        printf("WaitForMultipleObjects failed: %d\n",
                            GetLastError());
                        return 1;
                    }
                    for(i = 0; i < lenum.length; i++)
                    {
                        if (ncb[i].ncb_cmd_cplt == NRC_PENDING)
                            Cancel(&ncb[i]);
                        else
                        {
                            ncb[i].ncb_buffer[ncb[i].ncb_length] = 0;
                            FormatNetbiosName(ncb[i].ncb_callname, 
                                szSender);
                            printf("%03d [LANA %d] Message: '%s' "
								"received from: %s\n", j,
								ncb[i].ncb_lana_num, 
                                szMessageArray[i], szSender);
                        }
                        ResetEvent(hEvent[i]);
                    }
                }
            }
        }
        else
        {
            if (bOneLana)
            {
                // Make a blocking datagram receive on the specified
                // LANA number.
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    if (bRecvAny)
                    {
                        // Receive data destined for any NetBIOS name
                        // in this process's name table.
                        //
                        if (DatagramRecv(&ncb[0], dwOneLana, 0xFF, 
                            szMessageArray[0], MAX_DATAGRAM_SIZE,
                            NULL) != NRC_GOODRET)
                            return 1;
                    }
                    else
                    {
                        if (DatagramRecv(&ncb[0], dwOneLana,
							dwNum[0], szMessageArray[0],
							MAX_DATAGRAM_SIZE, NULL) 
							!= NRC_GOODRET)
                            return 1;
                    }
                    FormatNetbiosName(ncb[0].ncb_callname, szSender);
                    printf("%03d [LANA %d] Message: '%s' "
						   "received from: %s\n", j,
						   ncb[0].ncb_lana_num, szMessageArray[0],
						   szSender);
                }
            }
            else
            {
                // Post asynchronous datagram receives on each LANA
                // available. For all those commands that succeeded,
                // print the data, otherwise cancel the command.
                //
                for(j = 0; j < dwNumDatagrams; j++)
                {
                    for(i = 0; i < lenum.length; i++)
                    {
                        if (bRecvAny)
                        {
                            // Receive data destined for any NetBIOS 
                            // name in this process's name table.
                            // 
                            if (DatagramRecv(&ncb[i], lenum.lana[i],
								0xFF, szMessageArray[i],
								MAX_DATAGRAM_SIZE, hEvent[i])
								!= NRC_GOODRET)
                                return 1;
                        }
                        else
                        {
                            if (DatagramRecv(&ncb[i], lenum.lana[i],
								dwNum[i], szMessageArray[i],
								MAX_DATAGRAM_SIZE, hEvent[i])
								!= NRC_GOODRET)
                                return 1;
                        }
                    }
                    dwRet = WaitForMultipleObjects(lenum.length, 
                        hEvent, FALSE, INFINITE);
                    if (dwRet == WAIT_FAILED)
                    {
                        printf("WaitForMultipleObjects failed: %d\n",
                            GetLastError());
                        return 1;
                    }
                    for(i = 0; i < lenum.length; i++)
                    {
                        if (ncb[i].ncb_cmd_cplt == NRC_PENDING)
                            Cancel(&ncb[i]);
                        else
                        {
                            ncb[i].ncb_buffer[ncb[i].ncb_length] = 0;
                            FormatNetbiosName(ncb[i].ncb_callname, 
                                szSender);
                            printf("%03d [LANA %d] Message: '%s' "
								"from: %s\n", j, ncb[i].ncb_lana_num,
                                szMessageArray[i], szSender);
                        }
                        ResetEvent(hEvent[i]);
                    }
                }
            }
        }
        // Clean up
        //
        for(i = 0; i < lenum.length; i++)
        {
            CloseHandle(hEvent[i]);
            GlobalFree(szMessageArray[i]);
        }
        GlobalFree(hEvent);
        GlobalFree(szMessageArray);
    }
    // Clean things up
    //
    if (bOneLana)
        DelName(dwOneLana, szLocalName);
    else
    {
        for(i = 0; i < lenum.length; i++)
            DelName(lenum.lana[i], szLocalName);
    }
    GlobalFree(dwNum);

    return 0;
}

One Comment

Leave a Reply