|
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 $
|
Copyright © 2001-2003 Christopher R. Hertel
Released under the terms of the
LGPL
|
|