Listing 1.10
A Broadcast Name Registration


#include <stdio.h>
#include <stdlib.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "NS_Header.h"
#include "NS_Qrec.h"
#include "NS_Rrec.h"
#include "NS_RDaddr.h"


#define NBT_BCAST_ADDR "255.255.255.255"

#define uchar  unsigned char
#define ushort unsigned short


int BuildRegMsg( uchar         *msg,
                 const uchar   *name,
                 struct in_addr addr )
  /* ---------------------------------------------------- **
   * Create a Bcast Name Registration Message.
   *
   * This function hard-codes several values.
   * Obviously, a "real" implementation would need
   * to be much more flexible.
   * ---------------------------------------------------- **
   */
  {
  ushort *hdr = (ushort *)msg;
  uchar  *rrec;
  ushort  flags;
  int     len;
  int     rr_len;

  flags = OPCODE_REGISTER | NM_RD_BIT | NM_B_BIT;

  Put_NS_TID( hdr, 1964 );
  Put_NS_Hdr_Flags( hdr, flags );
  Put_NS_Hdr_Rec_Counts( hdr, (QUERYREC | ADDREC) );
  len = 12;     /* Fixed size of header. */

  len += Put_Qrec( &msg[len],  /* Query Rec Pointer  */
                   name,       /* NetBIOS name       */
                   ' ',        /* Padding char       */
                   '\0',       /* Suffix             */
                   "",         /* Scope ID           */
                   QTYPE_NB ); /* Qtype: Name        */

  rrec = &msg[len];
  rr_len  = Put_RRec_LSP( rrec, RRTYPE_NB );
  rr_len += Put_RRec_TTL( rrec, rr_len, 0 );
  rr_len += Put_RDLength( rrec, rr_len, 6 );
  rr_len += Put_RD_Addr(  rrec, rr_len, ONT_B, addr );

  return( len + rr_len );
  } /* BuildRegMsg */


void ReadRegReply( int sock )
  /* ---------------------------------------------------- **
   * Read a reply packet, and verify that it contains the
   * expected RCODE value.
   * ---------------------------------------------------- **
   */
  {
  uchar  bufr[512];
  int    msglen;
  ushort flags;

  msglen = recv( sock, bufr, 512, 0 );
  if( msglen < 0 )
    {
    perror( "recv()" );
    exit( EXIT_FAILURE );
    }

  if( msglen < 12 )
    {
    printf( "Truncated reply received.\n" );
    exit( EXIT_FAILURE );
    }

  flags = Get_NS_Hdr_Flags( (ushort *)bufr );
  switch( RCODE_MASK & flags )
    {
    case RCODE_ACT_ERR:
      /* This is the only valid Rcode in response to
       * a broadcast name registration request.
       */
      printf( "RCODE_ACT_ERR: Name is in use.\n" );
      break;
    default:
      printf( "Unexpected return code: 0x%.2x.\n",
              (RCODE_MASK & flags) );
      break;
    }
  } /* ReadRegReply */


int OpenSocket()
  /* ---------------------------------------------------- **
   * Open the UDP socket, enable broadcast, and bind the
   * socket to a high-numbered UDP port so that we can
   * listen for replies.
   * ---------------------------------------------------- **
   */
  {
  int                s;
  int                test = 1;
  struct sockaddr_in sox;

  s = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
  if( s < 0 )
    {
    perror( "socket()" );
    exit( EXIT_FAILURE );
    }

  if( setsockopt( s, SOL_SOCKET, SO_BROADCAST,
                  &test, sizeof(int) ) < 0 )
    {
    perror( "setsockopt()" );
    exit( EXIT_FAILURE );
    }

  sox.sin_addr.s_addr = INADDR_ANY;
  sox.sin_family      = AF_INET;
  sox.sin_port        = 0;  /* 0 == any port */
  test = bind( s, (struct sockaddr *)&sox,
               sizeof(struct sockaddr_in) );
  if( test < 0 )
    {
    perror( "bind()" );
    exit( EXIT_FAILURE );
    }

  return( s );
  } /* OpenSocket */


void SendBcastMsg( int sock, uchar *msg, int msglen )
  /* ---------------------------------------------------- **
   * Nice front-end to the sendto(2) function.
   * ---------------------------------------------------- **
   */
  {
  int                result;
  struct sockaddr_in to;

  if( 0 == inet_aton( NBT_BCAST_ADDR, &(to.sin_addr) ) )
    {
    printf( "Invalid destination IP address.\n" );
    exit( EXIT_FAILURE );
    }
  to.sin_family = AF_INET;
  to.sin_port   = htons( 137 );
  result = sendto( sock, (void *)msg, msglen, 0,
                   (struct sockaddr *)&to,
                   sizeof(struct sockaddr_in) );
  if( result < 0 )
    {
    perror( "sendto()" );
    exit( EXIT_FAILURE );
    }
  } /* SendBcastMsg */


int AwaitResponse( int sock, int milliseconds )
  /* ---------------------------------------------------- **
   * Wait for an incoming message.
   * One ms == 1/1000 second.
   * ---------------------------------------------------- **
   */
  {
  int           result;
  struct pollfd pfd[1];

  pfd->fd     = sock;
  pfd->events = POLLIN;
  result = poll( pfd, 1, milliseconds );
  if( result < 0 )
    {
    perror( "poll()" );
    exit( EXIT_FAILURE );
    }

  return( result );
  } /* AwaitResponse */


int main( int argc, char *argv[] )
  /* ---------------------------------------------------- **
   * This program demonstrates a Broadcast NBT Name
   * Registration.
   * ---------------------------------------------------- **
   */
  {
  int            i;
  int            result;
  int            ns_sock;
  int            msg_len;
  uchar          bufr[512];
  uchar         *name;
  struct in_addr address;

  if( argc != 3 )
    {
    printf( "Usage:  %s <name> <IP>\n", argv[0] );
    exit( EXIT_FAILURE );
    }

  name = (uchar *)argv[1];
  if( 0 == inet_aton( argv[2], &address ) )
    {
    printf( "Invalid IP.\n" );
    printf( "Usage:  %s <name> <IP>\n", argv[0] );
    exit( EXIT_FAILURE );
    }

  ns_sock = OpenSocket();

  msg_len = BuildRegMsg( bufr, name, address );

  for( i = 0; i < 3; i++ )
    {
    printf( "Trying...\n" );
    SendBcastMsg( ns_sock, bufr, msg_len );
    result = AwaitResponse( ns_sock, 750 );
    if( result )
      {
      ReadRegReply( ns_sock );
      exit( EXIT_FAILURE );
      }
    }
  printf( "Success: No negative replies received.\n" );

  /* Turn off RD bit for NAME OVERWRITE DEMAND. */
  Put_NS_Hdr_Flags( (ushort *)bufr,
                    OPCODE_REGISTER | NM_B_BIT );
  SendBcastMsg( ns_sock, bufr, msg_len );

  close( ns_sock );
  return( EXIT_SUCCESS );
  } /* main */


$Revision: 1.14 $
$Date: 2003/02/18 21:43:58 $
[W3C Validated] Copyright © 2001-2003 Christopher R. Hertel 
Released under the terms of the LGPL