Datagram Operations

Datagram Operations

Datagrams are connectionless methods of communication. A sender merely addresses each packet with its destination NetBIOS name and sends it on its way. No checking is performed to ensure data integrity, order of arrival, or reliability.

There are three ways to send a datagram. The first is to direct the datagram at a specific (unique or group) name. This means that only the process that registered the destination name can receive that datagram. The second method is to send a datagram to a group name. Only those processes that registered the given group name will be able to receive the message. Finally, the third way to send a datagram is to broadcast it to the entire network. Any process on any workstation on the LAN can receive the datagram. Sending a datagram to either a unique or a group name uses the NCBDGSEND command, whereas broadcasts use the NCBDGSENDBC command.

Using any of the datagram send commands is a simple process. Set the ncb_num field to the name number returned from an NCBADDNAME command or using events. For each LANA, the code posts an asynchronous NCBDGRECV (or NCBDGRECVBC) and waits until one succeeds, at which point it checks all posted commands, prints the messages for those that succeed, and cancels those commands that are still pending. The following example provides functions for both directed and broadcast sends and receives. The program can be compiled into a sample application that can be configured to send or receive datagrams. The program accepts several command-line parameters that allow the user to specify the number of datagrams to send or receive, the delay between sends, the use of broadcasts instead of directed datagrams, the receipt of datagrams for any name, and so on.

// Nbdgram.c #include <windows.h> #include <stdio.h> #include <stdlib.h> #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]; // Recipient's NetBIOS name DWORD  dwNumDatagrams = 25,           // Number of datagrams to send        dwOneLana,                     // If using one LANA, which one?        dwDelay = 0;                   // Delay between datagram sends // // 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':        // # of 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 the 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 toward the //    name represented by num. Data is copied into the supplied buffer. //    If hEvent is not 0, the receive call is made asynchronously //    with the supplied event handle. If num is 0xFF, 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 0,  //    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 on only one LANA, register the name     // on only that specified LANA; otherwise, register it on all      // LANAs     //      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 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; }

Once you've compiled the example, run the following tests to get an idea of how datagrams work. For learning purposes, you should run two instances of the applications, but on separate machines. If you run them on the same machine, they'll work, but this hides some important concepts. When run on the same machine, the LANA numbers for each side correspond to the same protocol. It's more interesting when they don't. Table 17-5 lists some commands to try, and Table 17-6 lists all the command-line options available for use with the sample program.

Table 17-5 NBDGRAM.C Commands

Client Command

Server Command

Nbdgram /n:CLIENT01

Nbdgram /s /n:SERVER01 /r:CLIENT01

Nbdgram /n:CLIENT01 /b

Nbdgram /s /n:SERVER01 /b

Nbdgram /g:CLIENTGROUP

Nbdgram /s /r:CLIENTGROUP


Table 17-6 Command Parameters for NBDGRAM.C

Flag

Meaning

/n:my-name

Register the unique name my-name.

/g:group-name

Register the group name group-name.

/s

Send datagrams (by default, the sample receives datagrams).

/c:n

Send or receive n number of datagrams.

/r:receiver

Specify the NetBIOS name to send the datagrams to.

/b

Use broadcast datagrams.

/a

Post receives for any NetBIOS name (set ncb_num to 0xFF).

/l:n

Perform all operations on LANA n only (by default, all sends and receives are posted on each LANA).

/d:n

Wait n milliseconds between sends.

For the third command in Table 17-5, run several clients on various machines. This illustrates one server sending one message to a group, and each member of the group waiting for data will receive the message. Also, try various combinations of the listed commands with the /l:x command-line option, where x is a valid LANA number. This command-line option switches the program's mode from performing the commands on all LANAs to performing the commands on the listed LANA only. For example, the command Nbdgram /n:CLIENT01 /l:0 makes the application listen only for incoming datagrams on LANA 0 and ignore any data arriving on any other LANA. Additionally, option /a is meaningful only to the clients. This flag causes the receive command to pick up incoming datagrams destined for any NetBIOS name registered by the process. In our example, this isn't very meaningful because the client registers only one name, but you can at least see how this would be coded. You might want to try modifying the code so that it registers a name for every /n:name option in the command line. Start up the server with the recipient flag set to only one of the names that the client registered. The client will receive the data, even though the NCBDGRECV command does not specifically refer to a particular name.



Network Programming for Microsoft Windows
Network Programming for Microsoft Windows (Microsoft Professional Series)
ISBN: 0735605602
EAN: 2147483647
Year: 2001
Pages: 172
Authors: Anthony Jones

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net