Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
protocol.cxx
Package: win2ksrc.rar [view]
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 62k
Category:
Windows Develop
Development Platform:
Visual C++
- /*++
- Copyright (c) 1994 Microsoft Corporation
- Module Name:
- protocol.cxx
- Abstract:
- This module contains the server to client protocol for DHCP.
- Author:
- Manny Weiser (mannyw) 21-Oct-1992
- Environment:
- User Mode - Win32
- Revision History:
- Madan Appiah (madana) 21-Oct-1993
- Arthur Bierer (arthurbi) 15-July-1998
- hacked up to use with Wininet's auto-proxy detection code
- --*/
- #include <wininetp.h>
- #include "aproxp.h"
- #include "apdetect.h"
- #ifndef VXD
- // ping routines.. ICMP
- #include <ipexport.h>
- //#include <icmpif.h>
- #include <icmpapi.h>
- #endif
- #ifdef NEWNT
- extern BOOL DhcpGlobalIsService;
- #endif // NEWNT
- DWORD // Time in seconds
- DhcpCalculateWaitTime( // how much time to wait
- IN DWORD RoundNum, // which round is this
- OUT DWORD *WaitMilliSecs // if needed the # in milli seconds
- );
- POPTION
- FormatDhcpInform(
- PDHCP_CONTEXT DhcpContext
- );
- DWORD
- SendDhcpInform(
- PDHCP_CONTEXT DhcpContext,
- PDWORD TransactionId
- );
- DWORD // status
- SendInformAndGetReplies( // send an inform packet and collect replies
- IN PDHCP_CONTEXT DhcpContext, // the context to send out of
- IN DWORD nInformsToSend,// how many informs to send?
- IN DWORD MaxAcksToWait, // how many acks to wait for
- OUT DHCP_EXPECTED_OPTIONS *pExpectedOptions // list of things parsed out of request
- );
- VOID
- DhcpExtractFullOrLiteOptions( // Extract some important options alone or ALL
- IN PDHCP_CONTEXT DhcpContext,
- IN LPBYTE OptStart, // start of the options stuff
- IN DWORD MessageSize, // # of bytes of options
- IN BOOL LiteOnly, // next struc is EXPECTED_OPTIONS and not FULL_OPTIONS
- OUT LPVOID DhcpOptions, // this is where the options would be stored
- IN OUT PLIST_ENTRY RecdOptions, // if !LiteOnly this gets filled with all incoming options
- IN OUT DWORD *LeaseExpiry, // if !LiteOnly input expiry time, else output expiry time
- IN LPBYTE ClassName, // if !LiteOnly this is used to add to the option above
- IN DWORD ClassLen // if !LiteOnly this gives the # of bytes of classname
- );
- DWORD
- SendDhcpMessage(
- PDHCP_CONTEXT DhcpContext,
- DWORD MessageLength,
- PDWORD TransactionId
- );
- DWORD
- OpenDhcpSocket(
- PDHCP_CONTEXT DhcpContext
- );
- DWORD
- GetSpecifiedDhcpMessage(
- PDHCP_CONTEXT DhcpContext,
- PDWORD BufferLength,
- DWORD TransactionId,
- DWORD TimeToWait
- );
- DWORD
- CloseDhcpSocket(
- PDHCP_CONTEXT DhcpContext
- );
- //
- // functions
- //
- DWORD // Time in seconds
- DhcpCalculateWaitTime( // how much time to wait
- IN DWORD RoundNum, // which round is this
- OUT DWORD *WaitMilliSecs // if needed the # in milli seconds
- ) {
- DWORD MilliSecs;
- //DWORD WaitTimes[4] = { 4000, 8000, 16000, 32000 };
- DWORD WaitTimes[4] = { 2000, 4000, 8000, 16000 };
- if( WaitMilliSecs ) *WaitMilliSecs = 0;
- if( RoundNum >= sizeof(WaitTimes)/sizeof(WaitTimes[0]) )
- return 0;
- MilliSecs = WaitTimes[RoundNum] - 1000 + ((rand()*((DWORD) 2000))/RAND_MAX);
- if( WaitMilliSecs ) *WaitMilliSecs = MilliSecs;
- return (MilliSecs + 501)/1000;
- }
- VOID _inline
- ConcatOption(
- IN OUT LPBYTE *Buf, // input buffer to re-alloc
- IN OUT ULONG *BufSize, // input buffer size
- IN BYTE UNALIGNED *Data, // data to append
- IN ULONG DataSize // how many bytes to add?
- )
- {
- LPBYTE NewBuf;
- ULONG NewSize;
- NewSize = (*BufSize) + DataSize;
- NewBuf = (LPBYTE) DhcpAllocateMemory(NewSize);
- if( NULL == NewBuf ) { // could not alloc memory?
- return; // can't do much
- }
- memcpy(NewBuf, *Buf, *BufSize); // copy existing part
- memcpy(NewBuf + *BufSize, Data, DataSize); // copy new stuff
- if( NULL != *Buf ) DhcpFreeMemory(*Buf); // if we alloc'ed mem, free it now
- *Buf = NewBuf;
- *BufSize = NewSize; // fill in new values..
- }
- VOID
- DhcpExtractFullOrLiteOptions( // Extract some important options alone or ALL
- IN PDHCP_CONTEXT DhcpContext, // input context
- IN LPBYTE OptStart, // start of the options stuff
- IN DWORD MessageSize, // # of bytes of options
- IN BOOL LiteOnly, // next struc is EXPECTED_OPTIONS and not FULL_OPTIONS
- OUT LPVOID DhcpOptions, // this is where the options would be stored
- IN OUT PLIST_ENTRY RecdOptions, // if !LiteOnly this gets filled with all incoming options
- IN OUT DWORD *LeaseExpiry, // if !LiteOnly input expiry time, else output expiry time
- IN LPBYTE ClassName, // if !LiteOnly this is used to add to the option above
- IN DWORD ClassLen // if !LiteOnly this gives the # of bytes of classname
- ) {
- BYTE UNALIGNED* ThisOpt;
- BYTE UNALIGNED* NextOpt;
- BYTE UNALIGNED* EndOpt;
- BYTE UNALIGNED* MagicCookie;
- DWORD Error;
- DWORD Size, ThisSize, UClassSize = 0;
- LPBYTE UClass= NULL; // concatenation of all OPTION_USER_CLASS options
- PDHCP_EXPECTED_OPTIONS ExpOptions;
- PDHCP_FULL_OPTIONS FullOptions;
- BYTE ReqdCookie[] = {
- (BYTE)DHCP_MAGIC_COOKIE_BYTE1,
- (BYTE)DHCP_MAGIC_COOKIE_BYTE2,
- (BYTE)DHCP_MAGIC_COOKIE_BYTE3,
- (BYTE)DHCP_MAGIC_COOKIE_BYTE4
- };
- EndOpt = OptStart + MessageSize; // all options should be < EndOpt;
- ExpOptions = (PDHCP_EXPECTED_OPTIONS)DhcpOptions;
- FullOptions = (PDHCP_FULL_OPTIONS)DhcpOptions;
- RtlZeroMemory((LPBYTE)DhcpOptions, LiteOnly?sizeof(*ExpOptions):sizeof(*FullOptions));
- // if(!LiteOnly) InitializeListHead(RecdOptions); -- clear off this list for getting ALL options
- // dont clear off options... just accumulate over..
- MagicCookie = OptStart;
- if( 0 == MessageSize ) goto DropPkt; // nothing to do in this case
- if( 0 != memcmp(MagicCookie, ReqdCookie, sizeof(ReqdCookie)) )
- goto DropPkt; // oops, cant handle this packet
- NextOpt = &MagicCookie[sizeof(ReqdCookie)];
- while( NextOpt < EndOpt && OPTION_END != *NextOpt ) {
- if( OPTION_PAD == *NextOpt ) { // handle pads right away
- NextOpt++;
- continue;
- }
- ThisOpt = NextOpt; // take a good look at this option
- if( NextOpt + 2 > EndOpt ) { // goes over boundary?
- break;
- }
- NextOpt += 2 + (unsigned)ThisOpt[1]; // Option[1] holds the size of this option
- Size = ThisOpt[1];
- if( NextOpt > EndOpt ) { // illegal option that goes over boundary!
- break; // ignore the error, but dont take this option
- }
- if(!LiteOnly) do { // look for any OPTION_MSFT_CONTINUED ..
- if( NextOpt >= EndOpt ) break; // no more options
- if( OPTION_MSFT_CONTINUED != NextOpt[0] ) break;
- if( NextOpt + 1 + NextOpt[1] > EndOpt ) {
- NextOpt = NULL; // do this so that we know to quit at the end..
- break;
- }
- NextOpt++; // skip opt code
- ThisSize = NextOpt[0]; // # of bytes to shift back..
- memcpy(ThisOpt+2+Size, NextOpt+1,ThisSize);
- NextOpt += ThisSize+1;
- Size += ThisSize;
- } while(1); // keep stringing up any "continued" options..
- if( NULL == NextOpt ) { // err parsing OPTION_MSFT_CONTINUED ..
- break;
- }
- if( LiteOnly ) { // handle the small subnet of options
- switch( ThisOpt[0] ) { // ThisOpt[0] is OptionId, ThisOpt[1] is size
- case OPTION_MESSAGE_TYPE:
- if( ThisOpt[1] != 1 ) goto DropPkt;
- ExpOptions->MessageType = &ThisOpt[2];
- continue;
- case OPTION_SUBNET_MASK:
- if( ThisOpt[1] != sizeof(DWORD) ) goto DropPkt;
- ExpOptions->SubnetMask = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- continue;
- case OPTION_LEASE_TIME:
- if( ThisOpt[1] != sizeof(DWORD) ) goto DropPkt;
- ExpOptions->LeaseTime = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- continue;
- case OPTION_SERVER_IDENTIFIER:
- if( ThisOpt[1] != sizeof(DWORD) ) goto DropPkt;
- ExpOptions->ServerIdentifier = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- continue;
- case OPTION_DOMAIN_NAME:
- if( ThisOpt[1] == 0 ) goto DropPkt;
- ExpOptions->DomainName = (BYTE UNALIGNED *)&ThisOpt[2];
- ExpOptions->DomainNameSize = ThisOpt[1];
- break;
- case OPTION_WPAD_URL:
- if( ThisOpt[1] == 0 ) goto DropPkt;
- ExpOptions->WpadUrl = (BYTE UNALIGNED *)&ThisOpt[2];
- ExpOptions->WpadUrlSize = ThisOpt[1];
- break;
- default:
- continue;
- }
- } else { // Handle the full set of options
- switch( ThisOpt[0] ) {
- case OPTION_MESSAGE_TYPE:
- if( Size != 1 ) goto DropPkt;
- FullOptions->MessageType = &ThisOpt[2];
- break;
- case OPTION_SUBNET_MASK:
- if( Size != sizeof(DWORD) ) goto DropPkt;
- FullOptions->SubnetMask = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_LEASE_TIME:
- if( Size != sizeof(DWORD) ) goto DropPkt;
- FullOptions->LeaseTime = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_SERVER_IDENTIFIER:
- if( Size != sizeof(DWORD) ) goto DropPkt;
- FullOptions->ServerIdentifier = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_RENEWAL_TIME: // T1Time
- if( Size != sizeof(DWORD) ) goto DropPkt;
- FullOptions->T1Time = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_REBIND_TIME: // T2Time
- if( Size != sizeof(DWORD) ) goto DropPkt;
- FullOptions->T2Time = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_ROUTER_ADDRESS:
- if( Size < sizeof(DWORD) || (Size % sizeof(DWORD) ) )
- goto DropPkt; // There can be many router addresses
- FullOptions->GatewayAddresses = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- FullOptions->nGateways = Size / sizeof(DWORD);
- break;
- case OPTION_STATIC_ROUTES:
- if( Size < 2*sizeof(DWORD) || (Size % (2*sizeof(DWORD))) )
- goto DropPkt; // the static routes come in pairs
- FullOptions->StaticRouteAddresses = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- FullOptions->nStaticRoutes = Size/(2*sizeof(DWORD));
- break;
- case OPTION_DYNDNS_BOTH:
- if( Size < 3 ) goto DropPkt;
- FullOptions->DnsFlags = (BYTE UNALIGNED *)&ThisOpt[2];
- FullOptions->DnsRcode1 = (BYTE UNALIGNED *)&ThisOpt[3];
- FullOptions->DnsRcode2 = (BYTE UNALIGNED *)&ThisOpt[3];
- break;
- case OPTION_DOMAIN_NAME:
- if( Size == 0 ) goto DropPkt;
- FullOptions->DomainName = (BYTE UNALIGNED *)&ThisOpt[2];
- FullOptions->DomainNameSize = Size;
- break;
- case OPTION_WPAD_URL:
- if( Size == 0 ) goto DropPkt;
- FullOptions->WpadUrl = (BYTE UNALIGNED *)&ThisOpt[2];
- FullOptions->WpadUrlSize = Size;
- break;
- case OPTION_DOMAIN_NAME_SERVERS:
- if( Size < sizeof(DWORD) || (Size % sizeof(DWORD) ))
- goto DropPkt;
- FullOptions->DnsServerList = (DHCP_IP_ADDRESS UNALIGNED *)&ThisOpt[2];
- FullOptions->nDnsServers = Size / sizeof(DWORD);
- break;
- case OPTION_MESSAGE:
- if( Size == 0 ) break; // ignore zero sized packets
- FullOptions->ServerMessage = &ThisOpt[2];
- FullOptions->ServerMessageLength = ThisOpt[1];
- break;
- case OPTION_MCAST_LEASE_START:
- if ( Size != sizeof(DATE_TIME) ) goto DropPkt;
- FullOptions->MCastLeaseStartTime = (DWORD UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_MCAST_TTL:
- if ( Size != 1 ) goto DropPkt;
- FullOptions->MCastTTL = (BYTE UNALIGNED *)&ThisOpt[2];
- break;
- case OPTION_USER_CLASS:
- if( Size <= 6) goto DropPkt;
- ConcatOption(&UClass, &UClassSize, &ThisOpt[2], Size);
- continue; // don't add this option yet...
- default:
- // unknowm message, nothing to do.. especially dont log this
- break;
- }
- } // if LiteOnly then else
- } // while NextOpt < EndOpt
- if( LiteOnly && LeaseExpiry ) { // If asked to calculate lease expiration time..
- DWORD LeaseTime;
- time_t TimeNow, ExpirationTime;
- // BBUGBUGBUG [arthurbi] broken intensionlly, dead code.
- //if( ExpOptions->LeaseTime ) LeaseTime = _I_ntohl(*ExpOptions->LeaseTime);
- if( ExpOptions->LeaseTime ) LeaseTime = 0;
- else LeaseTime = DHCP_MINIMUM_LEASE;
- ExpirationTime = (TimeNow = time(NULL)) + (time_t)LeaseTime;
- if( ExpirationTime < TimeNow ) {
- ExpirationTime = INFINIT_TIME;
- }
- *LeaseExpiry = (DWORD)ExpirationTime ;
- }
- if( !LiteOnly && NULL != UClass ) { // we have a user class list to pass on..
- DhcpAssert(UClassSize != 0 ); // we better have something here..
- DhcpFreeMemory(UClass); UClass = NULL;
- }
- return;
- DropPkt:
- RtlZeroMemory(DhcpOptions, LiteOnly?sizeof(ExpOptions):sizeof(FullOptions));
- if( LiteOnly && LeaseExpiry ) *LeaseExpiry = (DWORD) time(NULL) + DHCP_MINIMUM_LEASE;
- //if(!LiteOnly) DhcpFreeAllOptions(RecdOptions);// ok undo the options that we just added
- if(!LiteOnly && NULL != UClass ) DhcpFreeMemory(UClass);
- }
- POPTION // ptr to add additional options
- FormatDhcpInform( // format the packet for an INFORM
- IN PDHCP_CONTEXT DhcpContext // format for this context
- ) {
- LPOPTION option;
- LPBYTE OptionEnd;
- BYTE value;
- PDHCP_MESSAGE dhcpMessage;
- dhcpMessage = DhcpContext->MessageBuffer;
- RtlZeroMemory( dhcpMessage, DHCP_SEND_MESSAGE_SIZE );
- //
- // BUGBUG [arthurbi] -
- // For RAS client, use broadcast bit, otherwise the router will try
- // to send as unicast to made-up RAS client hardware address, which
- // will not work. So will this work without it?
- //
- //
- // Transaction ID is filled in during send
- //
- dhcpMessage->Operation = BOOT_REQUEST;
- dhcpMessage->HardwareAddressType = DhcpContext->HardwareAddressType;
- dhcpMessage->SecondsSinceBoot = (WORD) DhcpContext->SecondsSinceBoot;
- memcpy(dhcpMessage->HardwareAddress,DhcpContext->HardwareAddress,DhcpContext->HardwareAddressLength);
- dhcpMessage->HardwareAddressLength = (BYTE)DhcpContext->HardwareAddressLength;
- dhcpMessage->ClientIpAddress = DhcpContext->IpAddress;
- //dhcpMessage->Reserved = 0;
- //dhcpMessage->Reserved = _I_htons(DHCP_BROADCAST);
- //if ( IS_MDHCP_CTX(DhcpContext ) ) MDHCP_MESSAGE( dhcpMessage );
- option = &dhcpMessage->Option;
- OptionEnd = (LPBYTE)dhcpMessage + DHCP_SEND_MESSAGE_SIZE;
- //
- // always add magic cookie first
- //
- option = (LPOPTION) DhcpAppendMagicCookie( (LPBYTE) option, OptionEnd );
- value = DHCP_INFORM_MESSAGE;
- option = DhcpAppendOption(
- option,
- OPTION_MESSAGE_TYPE,
- &value,
- 1,
- OptionEnd
- );
- //
- // BUGBUG [arthurbi], shouldn't we uncomment this?
- //
- // un comment later on
- /*option = DhcpAppendClassIdOption(
- DhcpContext,
- (LPBYTE)option,
- OptionEnd
- );*/
- return( option );
- }
- DWORD // status
- SendDhcpInform( // send an inform packet after filling required options
- IN PDHCP_CONTEXT DhcpContext, // sned out for this context
- IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
- ) {
- DWORD size;
- DWORD Error;
- POPTION option;
- LPBYTE OptionEnd;
- BYTE SentOpt[OPTION_END+1];
- BYTE SentVOpt[OPTION_END+1];
- BYTE VendorOpt[OPTION_END+1];
- DWORD VendorOptSize;
- RtlZeroMemory(SentOpt, sizeof(SentOpt)); // initialize boolean arrays
- RtlZeroMemory(SentVOpt, sizeof(SentVOpt)); // so that no option is presumed sent
- VendorOptSize = 0; // encapsulated vendor option is empty
- option = FormatDhcpInform( DhcpContext ); // core format
- OptionEnd = (LPBYTE)(DhcpContext->MessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
- if( DhcpContext->ClientIdentifier.fSpecified) // client id specified in registy
- option = DhcpAppendClientIDOption( // ==> use this client id as option
- option,
- DhcpContext->ClientIdentifier.bType,
- DhcpContext->ClientIdentifier.pbID,
- (BYTE)DhcpContext->ClientIdentifier.cbID,
- OptionEnd
- );
- else // client id was not specified
- option = DhcpAppendClientIDOption( // ==> use hw addr as client id
- option,
- DhcpContext->HardwareAddressType,
- DhcpContext->HardwareAddress,
- (BYTE)DhcpContext->HardwareAddressLength,
- OptionEnd
- );
- { // add hostname and comment options
- char szHostName[255];
- if ( _I_gethostname(szHostName, ARRAY_ELEMENTS(szHostName)) != SOCKET_ERROR )
- {
- option = DhcpAppendOption(
- option,
- OPTION_HOST_NAME,
- (LPBYTE)szHostName,
- (BYTE)((strlen(szHostName) + 1) * sizeof(CHAR)),
- OptionEnd
- );
- }
- }
- if( NULL != DhcpGlobalClientClassInfo ) { // if we have any info on client class..
- option = DhcpAppendOption(
- option,
- OPTION_CLIENT_CLASS_INFO,
- (LPBYTE)DhcpGlobalClientClassInfo,
- strlen(DhcpGlobalClientClassInfo),
- OptionEnd
- );
- }
- SentOpt[OPTION_MESSAGE_TYPE] = TRUE; // these must have been added by now
- if(DhcpContext->ClassIdLength) SentOpt[OPTION_USER_CLASS] = TRUE;
- SentOpt[OPTION_CLIENT_CLASS_INFO] = TRUE;
- SentOpt[OPTION_CLIENT_ID] = TRUE;
- SentOpt[OPTION_REQUESTED_ADDRESS] = TRUE;
- SentOpt[OPTION_HOST_NAME] = TRUE;
- option = DhcpAppendSendOptions( // append all other options we need to send
- DhcpContext, // for this context
- &DhcpContext->SendOptionsList, // this is the list of options to send out
- DhcpContext->ClassId, // which class.
- DhcpContext->ClassIdLength, // how many bytes are there in the class id
- (LPBYTE)option, // start of the buffer to add the options
- (LPBYTE)OptionEnd, // end of the buffer up to which we can add options
- SentOpt, // this is the boolean array that marks what opt were sent
- SentVOpt, // this is for vendor spec options
- VendorOpt, // this would contain some vendor specific options
- &VendorOptSize // the # of bytes of vendor options added to VendorOpt param
- );
- if( !SentOpt[OPTION_VENDOR_SPEC_INFO] && VendorOptSize && VendorOptSize <= OPTION_END )
- option = DhcpAppendOption( // add vendor specific options if we havent already sent it
- option,
- OPTION_VENDOR_SPEC_INFO,
- VendorOpt,
- (BYTE)VendorOptSize,
- OptionEnd
- );
- option = DhcpAppendOption( option, OPTION_END, NULL, 0, OptionEnd );
- size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MessageBuffer);
- return SendDhcpMessage( // finally send the message and return
- DhcpContext,
- size,
- pdwXid
- );
- }
- DWORD
- InitializeDhcpSocket(
- SOCKET *Socket,
- DHCP_IP_ADDRESS IpAddress
- )
- /*++
- Routine Description:
- This function initializes and binds a socket to the specified IP address.
- Arguments:
- Socket - Returns a pointer to the initialized socket.
- IpAddress - The IP address to bind the socket to. It is legitimate
- to bind a socket to 0.0.0.0 if the card has no current IP address.
- Return Value:
- The status of the operation.
- --*/
- {
- DWORD error;
- DWORD closeError;
- DWORD value;
- struct sockaddr_in socketName;
- DWORD i;
- SOCKET sock;
- //
- // Sockets initialization
- //
- sock = _I_socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
- if ( sock == INVALID_SOCKET ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("socket failed, error = %ldn", error ));
- return( error );
- }
- //
- // Make the socket share-able
- //
- value = 1;
- error = _I_setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&value, sizeof(value) );
- if ( error != 0 ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("setsockopt failed, err = %ldn", error ));
- closeError = _I_closesocket( sock );
- if ( closeError != 0 ) {
- DhcpPrint(("closesocket failed, err = %dn", closeError ));
- }
- return( error );
- }
- error = _I_setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char FAR *)&value, sizeof(value) );
- if ( error != 0 ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("setsockopt failed, err = %ldn", error ));
- closeError = _I_closesocket( sock );
- if ( closeError != 0 ) {
- DhcpPrint(("closesocket failed, err = %dn", closeError ));
- }
- return( error );
- }
- //
- // If the IpAddress is zero, set the special socket option to make
- // stack work with zero address.
- //
- if( IpAddress == 0 ) {
- value = 1234;
- error = _I_setsockopt( sock, SOL_SOCKET, 0x8000, (char FAR *)&value, sizeof(value) );
- if ( error != 0 ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("setsockopt failed, err = %ldn", error ));
- closeError = _I_closesocket( sock );
- if ( closeError != 0 ) {
- DhcpPrint(("closesocket failed, err = %dn", closeError ));
- }
- return( error );
- }
- }
- socketName.sin_family = PF_INET;
- socketName.sin_port = _I_htons( DHCP_CLIENT_PORT );
- socketName.sin_addr.s_addr = IpAddress;
- for ( i = 0; i < 8 ; i++ ) {
- socketName.sin_zero[i] = 0;
- }
- //
- // Bind this socket to the DHCP server port
- //
- error = _I_bind(
- sock,
- (struct sockaddr FAR *)&socketName,
- sizeof( socketName )
- );
- if ( error != 0 ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("bind failed (address 0x%lx), err = %ldn", IpAddress, error ));
- closeError = _I_closesocket( sock );
- if ( closeError != 0 ) {
- DhcpPrint(("closesocket failed, err = %dn", closeError ));
- }
- return( error );
- }
- *Socket = sock;
- return( NO_ERROR );
- }
- DWORD // status
- SendInformAndGetReplies( // send an inform packet and collect replies
- IN PDHCP_CONTEXT DhcpContext, // the context to send out of
- IN DWORD nInformsToSend,// how many informs to send?
- IN DWORD MaxAcksToWait, // how many acks to wait for
- OUT DHCP_EXPECTED_OPTIONS *pExpectedOptions // list of things parsed out of request
- ) {
- time_t StartTime;
- time_t TimeNow;
- DWORD TimeToWait;
- DWORD Error;
- DWORD Xid;
- DWORD MessageSize;
- DWORD RoundNum;
- DWORD MessageCount;
- DWORD LeaseExpirationTime;
- DHCP_FULL_OPTIONS FullOptions;
- DhcpPrint(("SendInformAndGetReplies enteredn"));
- if((Error = OpenDhcpSocket(DhcpContext)) != ERROR_SUCCESS) {
- DhcpPrint(("Could not open socket for this interface! (%ld)n", Error));
- return Error;
- }
- Xid = 0; // Will be generated by first SendDhcpPacket
- MessageCount = 0; // total # of messages we have got
- DhcpContext->SecondsSinceBoot = 0; // start at zero..
- for( RoundNum = 0; RoundNum < nInformsToSend; RoundNum ++ ) {
- Error = SendDhcpInform(DhcpContext, &Xid);
- if( ERROR_SUCCESS != Error ) {
- DhcpPrint(("SendDhcpInform: %ldn", Error));
- goto Cleanup;
- } else {
- DhcpPrint(("Sent DhcpInformn"));
- }
- TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
- DhcpContext->SecondsSinceBoot += TimeToWait; // do this so that next time thru it can go thru relays..
- StartTime = time(NULL);
- while ( TRUE ) { // wiat for the specified wait time
- MessageSize = DHCP_MESSAGE_SIZE;
- DhcpPrint(("Waiting for ACK[Xid=%x]: %ld secondsn",Xid, TimeToWait));
- Error = GetSpecifiedDhcpMessage( // try to receive an ACK
- DhcpContext,
- &MessageSize,
- Xid,
- (DWORD)TimeToWait
- );
- if ( Error == ERROR_SEM_TIMEOUT ) break;
- if( Error != ERROR_SUCCESS ) {
- DhcpPrint(("GetSpecifiedDhcpMessage: %ldn", Error));
- goto Cleanup;
- }
- DhcpExtractFullOrLiteOptions( // Need to see if this is an ACK
- DhcpContext,
- (LPBYTE)&DhcpContext->MessageBuffer->Option,
- MessageSize - DHCP_MESSAGE_FIXED_PART_SIZE,
- TRUE, // do lite extract only
- pExpectedOptions, // check for only expected options
- NULL, // unused
- &LeaseExpirationTime,
- NULL, // unused
- 0 // unused
- );
- if( NULL == pExpectedOptions->MessageType ) {
- DhcpPrint(("Received no message type!n"));
- } else if( DHCP_ACK_MESSAGE != *(pExpectedOptions->MessageType) ) {
- DhcpPrint(("Received unexpected message type: %ldn", *(pExpectedOptions->MessageType)));
- } else if( NULL == pExpectedOptions->ServerIdentifier ) {
- DhcpPrint(("Received no server identifier, dropping inform ACKn"));
- } else {
- MessageCount ++;
- DhcpPrint(("Received %ld ACKS so farn", MessageCount));
- DhcpExtractFullOrLiteOptions( // do FULL options..
- DhcpContext,
- (LPBYTE)&DhcpContext->MessageBuffer->Option,
- MessageSize - DHCP_MESSAGE_FIXED_PART_SIZE,
- FALSE,
- &FullOptions,
- &(DhcpContext->RecdOptionsList),
- &LeaseExpirationTime,
- DhcpContext->ClassId,
- DhcpContext->ClassIdLength
- );
- if( MessageCount >= MaxAcksToWait ) goto Cleanup;
- } // if( it is an ACK and ServerId present )
- TimeNow = time(NULL); // Reset the time values to reflect new time
- if( TimeToWait < (DWORD) (TimeNow - StartTime) ) {
- break; // no more time left to wait..
- }
- TimeToWait -= (DWORD)(TimeNow - StartTime); // recalculate time now
- StartTime = TimeNow; // reset start time also
- } // end of while ( TimeToWait > 0)
- } // for (RoundNum = 0; RoundNum < nInformsToSend ; RoundNum ++ )
- Cleanup:
- CloseDhcpSocket(DhcpContext);
- if( MessageCount ) Error = ERROR_SUCCESS;
- DhcpPrint(("SendInformAndGetReplies: got %d ACKS (returning %ld)n", MessageCount,Error));
- return Error;
- }
- //--------------------------------------------------------------------------------
- // This function gets the options from the server using DHCP_INFORM message.
- // It picks the first ACK and then processes it.
- // It ignores any errors caused by TIME_OUTS as that only means there is no
- // server, or the server does not have this functionality. No point giving up
- // because of that.
- //--------------------------------------------------------------------------------
- BOOL // win32 status
- DhcpDoInform( // send an inform packet if necessary
- IN CAdapterInterface * pAdapterInterface,
- IN BOOL fBroadcast, // Do we broadcast this inform, or unicast to server?
- OUT LPSTR lpszAutoProxyUrl,
- IN DWORD dwAutoProxyUrlLength
- ) {
- DHCP_CONTEXT StackDhcpContext; // input context to do inform on
- PDHCP_CONTEXT DhcpContext = &StackDhcpContext;
- DWORD Error;
- DWORD LocalError;
- BOOL WasPlumbedBefore;
- time_t OldT2Time;
- DHCP_EXPECTED_OPTIONS ExpectedOptions;
- *lpszAutoProxyUrl = '';
- if ( ! pAdapterInterface->IsDhcp() ) {
- return FALSE;
- }
- if (! pAdapterInterface->CopyAdapterInfoToDhcpContext(DhcpContext) ) {
- return FALSE;
- }
- // mdhcp uses INADDR_ANY so it does not have to have an ipaddress.
- if( 0 == DhcpContext->IpAddress && !IS_MDHCP_CTX( DhcpContext) ) {
- DhcpPrint(("Cannot do DhcpInform on an adapter without ip address!n"));
- return FALSE;
- }
- // Open the socket ahead... so that things work. Tricky, else does not work!!!
- if((Error = OpenDhcpSocket(DhcpContext)) != ERROR_SUCCESS ) {
- DhcpPrint(("Could not open socket (%ld)n", Error));
- return FALSE;
- }
- // If you always need to broadcast this message, the KLUDGE is to
- // set pContext->T2Time = 0; and pContext->fFlags &= ~DHCP_CONTEXT_FLAGS_PLUMBED
- // and that should do the trick! Safe to change the struct as it was cloned.
- OldT2Time = DhcpContext->T2Time;
- WasPlumbedBefore = IS_ADDRESS_PLUMBED(DhcpContext);
- if(fBroadcast) {
- DhcpContext->T2Time = 0; // !!!! KLUDGE.. look at SendDhcpMessage to understand this ..
- ADDRESS_UNPLUMBED(DhcpContext);
- CONNECTION_BROADCAST(DhcpContext);
- } else {
- DhcpContext->T2Time = (-1);
- }
- memset((void *) &ExpectedOptions, 0, sizeof(DHCP_EXPECTED_OPTIONS));
- Error = SendInformAndGetReplies( // get replies on this
- DhcpContext, // context to send on
- 2, // send atmost 2 informs
- 1, // wait for as many as 4 packets..
- &ExpectedOptions
- );
- DhcpContext->LastInformSent = time(NULL); // record when the last inform was sent
- DhcpContext->T2Time = OldT2Time;
- if( WasPlumbedBefore ) ADDRESS_PLUMBED(DhcpContext);
- LocalError = CloseDhcpSocket(DhcpContext);
- DhcpAssert(ERROR_SUCCESS == LocalError);
- if( ERROR_SUCCESS != Error ) {
- DhcpPrint(("DhcpDoInform:return [0x%lx]n", Error));
- }
- else
- {
- //
- // Did we actually get a response with an URL that can be used ?
- //
- if ( ExpectedOptions.WpadUrl &&
- ExpectedOptions.WpadUrlSize > 0 &&
- dwAutoProxyUrlLength > ExpectedOptions.WpadUrlSize )
- {
- memcpy(lpszAutoProxyUrl, ExpectedOptions.WpadUrl, ExpectedOptions.WpadUrlSize );
- return TRUE;
- }
- }
- return FALSE;
- }
- DWORD
- SendDhcpMessage(
- PDHCP_CONTEXT DhcpContext,
- DWORD MessageLength,
- PDWORD TransactionId
- )
- /*++
- Routine Description:
- This function sends a UDP message to the DHCP server specified
- in the DhcpContext.
- Arguments:
- DhcpContext - A pointer to a DHCP context block.
- MessageLength - The length of the message to send.
- TransactionID - The transaction ID for this message. If 0, the
- function generates a random ID, and returns it.
- Return Value:
- The status of the operation.
- --*/
- {
- DWORD error;
- int i;
- struct sockaddr_in socketName;
- time_t TimeNow;
- BOOL LockedInterface = FALSE;
- if ( *TransactionId == 0 ) {
- *TransactionId = (rand() << 16) + rand();
- }
- DhcpContext->MessageBuffer->TransactionID = *TransactionId;
- //
- // Initialize the outgoing address.
- //
- socketName.sin_family = PF_INET;
- socketName.sin_port = _I_htons( DHCP_SERVR_PORT );
- if ( IS_MDHCP_CTX(DhcpContext) ) {
- socketName.sin_addr.s_addr = DhcpContext->DhcpServerAddress;
- if ( CLASSD_NET_ADDR( DhcpContext->DhcpServerAddress ) ) {
- int TTL = 16;
- //
- // Set TTL
- // MBUG: we need to read this from the registry.
- //
- if (_I_setsockopt(
- DhcpContext->Socket,
- IPPROTO_IP,
- IP_MULTICAST_TTL,
- (char *)&TTL,
- sizeof((int)TTL)) == SOCKET_ERROR){
- error = _I_WSAGetLastError();
- DhcpPrint(("could not set MCast TTL %ldn",error ));
- return error;
- }
- }
- } else if( IS_ADDRESS_PLUMBED(DhcpContext) &&
- !IS_MEDIA_RECONNECTED(DhcpContext) && // media reconnect - braodcast
- !IS_POWER_RESUMED(DhcpContext) ) { // power resumed - broadcast
- //
- // If we are past T2, use the broadcast address; otherwise,
- // direct this to the server.
- //
- TimeNow = time( NULL );
- // BUGBUG why did we broadcast here before ?
- if ( TimeNow > DhcpContext->T2Time && IS_CONNECTION_BROADCAST(DhcpContext)) {
- socketName.sin_addr.s_addr = (DHCP_IP_ADDRESS)(INADDR_BROADCAST);
- } else {
- socketName.sin_addr.s_addr = DhcpContext->DhcpServerAddress;
- }
- }
- else {
- socketName.sin_addr.s_addr = (DHCP_IP_ADDRESS)(INADDR_BROADCAST);
- INET_ASSERT(FALSE);
- }
- for ( i = 0; i < 8 ; i++ ) {
- socketName.sin_zero[i] = 0;
- }
- if( socketName.sin_addr.s_addr ==
- (DHCP_IP_ADDRESS)(INADDR_BROADCAST) ) {
- DWORD Error = ERROR_SUCCESS;
- DWORD InterfaceId;
- //
- // BUGBUG TODO [arthurbi] This code below is needed for
- // Broadcasts to work. We need to make some fancy driver
- // calls to work...
- //
- //
- // if we broadcast a message, inform IP stack - the adapter we
- // like to send this broadcast on, otherwise it will pick up the
- // first uninitialized adapter.
- //
- // InterfaceId = DhcpContext->IpInterfaceContext;
- //
- // if( !IPSetInterface( InterfaceId ) ) {
- // // DhcpAssert( FALSE );
- // Error = ERROR_GEN_FAILURE;
- // }
- // InterfaceId = ((PLOCAL_CONTEXT_INFO)
- // DhcpContext->LocalInformation)->IpInterfaceContext;
- //
- // LOCK_INTERFACE();
- // LockedInterface = TRUE;
- // Error = IPSetInterface( InterfaceId );
- // DhcpAssert( Error == ERROR_SUCCESS );
- if( ERROR_SUCCESS != Error ) {
- DhcpPrint(("IPSetInterface failed with %lx errorn", Error));
- UNLOCK_INTERFACE();
- return Error;
- }
- }
- //
- // send minimum DHCP_MIN_SEND_RECV_PK_SIZE (300) bytes, otherwise
- // bootp relay agents don't like the packet.
- //
- MessageLength = (MessageLength > DHCP_MIN_SEND_RECV_PK_SIZE) ?
- MessageLength : DHCP_MIN_SEND_RECV_PK_SIZE;
- error = _I_sendto(
- DhcpContext->Socket,
- (PCHAR)DhcpContext->MessageBuffer,
- MessageLength,
- 0,
- (struct sockaddr *)&socketName,
- sizeof( struct sockaddr )
- );
- #ifndef VXD
- if( LockedInterface ) { UNLOCK_INTERFACE(); }
- #endif VXD
- if ( error == SOCKET_ERROR ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("Send failed, error = %ldn", error ));
- } else {
- IF_DEBUG( PROTOCOL ) {
- DhcpPrint(("Sent message to %s: n", _I_inet_ntoa( socketName.sin_addr )));
- }
- DhcpDumpMessage( DEBUG_PROTOCOL_DUMP, DhcpContext->MessageBuffer );
- error = NO_ERROR;
- }
- return( error );
- }
- DWORD
- OpenDhcpSocket(
- PDHCP_CONTEXT DhcpContext
- )
- {
- DWORD Error;
- PLOCAL_CONTEXT_INFO localInfo;
- if ( DhcpContext->Socket != INVALID_SOCKET ) {
- return ( ERROR_SUCCESS );
- }
- //
- // create a socket for the dhcp protocol. it's important to bind the
- // socket to the correct ip address. There are currently three cases:
- //
- // 1. If the interface has been autoconfigured, it already has an address,
- // say, IP1. If the client receives a unicast offer from a dhcp server
- // the offer will be addressed to IP2, which is the client's new dhcp
- // address. If we bind the dhcp socket to IP1, the client won't be able
- // to receive unicast responses. So, we bind the socket to 0.0.0.0.
- // This will allow the socket to receive a unicast datagram addressed to
- // any address.
- //
- // 2. If the interface in not plumbed (i.e. doesn't have an address) bind
- // the socket to 0.0.0.0
- //
- // 3. If the interface has been plumbed has in *not* autoconfigured, then
- // bind to the current address.
- Error = InitializeDhcpSocket(
- &DhcpContext->Socket,
- DhcpContext->IpAddress
- );
- if( Error != ERROR_SUCCESS ) {
- DhcpContext->Socket = INVALID_SOCKET;
- DhcpPrint((" Socket Open failed, %ldn", Error ));
- }
- return(Error);
- }
- DWORD
- CloseDhcpSocket(
- PDHCP_CONTEXT DhcpContext
- )
- {
- DWORD Error = ERROR_SUCCESS;
- if( DhcpContext->Socket != INVALID_SOCKET ) {
- BOOL Bool;
- Error = _I_closesocket( DhcpContext->Socket );
- if( Error != ERROR_SUCCESS ) {
- DhcpPrint((" Socket close failed, %ldn", Error ));
- }
- DhcpContext->Socket = INVALID_SOCKET;
- //
- // Reset the IP stack to send DHCP broadcast to first
- // uninitialized stack.
- //
- //Bool = IPResetInterface();
- //DhcpAssert( Bool == TRUE );
- }
- return( Error );
- }
- typedef struct /* anonymous */ { // structure to hold waiting recvfroms
- LIST_ENTRY RecvList; // other elements in this list
- PDHCP_CONTEXT Ctxt; // which context is this wait for?
- DWORD InBufLen; // what was the buffer size to recv in?
- PDWORD BufLen; // how many bytes did we recvd?
- DWORD Xid; // what xid is this wait for?
- time_t ExpTime; // wait until what time?
- HANDLE WaitEvent; // event for waiting on..
- BOOL Recd; // was a packet received..?
- } RECV_CTXT, *PRECV_CTXT; // ctxt used to recv on..
- VOID
- InsertInPriorityList( // insert in priority list according to Secs
- IN OUT PRECV_CTXT Ctxt, // Secs field changed to hold offset
- IN PLIST_ENTRY List,
- OUT PBOOL First // adding in first location?
- )
- {
- PRECV_CTXT ThisCtxt;
- PLIST_ENTRY InitList; // "List" param at function entry
- if( IsListEmpty(List) ) { // no element in list? add this and quit
- *First = TRUE; // adding at head
- } else {
- *First = FALSE; // adding at tail..
- }
- InsertTailList( List, &Ctxt->RecvList); // insert element..
- //LeaveCriticalSection( &DhcpGlobalRecvFromCritSect );
- }
- DWORD
- TryReceive( // try to recv pkt on 0.0.0.0 socket
- IN SOCKET Socket, // socket to recv on
- IN LPBYTE Buffer, // buffer to fill
- OUT PDWORD BufLen, // # of bytes filled in buffer
- OUT PDWORD Xid, // Xid of recd pkt
- IN DWORD Secs // # of secs to spend waiting?
- )
- {
- DWORD Error;
- struct timeval timeout;
- fd_set SockSet;
- struct sockaddr SockName;
- int SockNameSize;
- FD_ZERO(&SockSet);
- FD_SET(Socket,&SockSet);
- SockNameSize = sizeof( SockName );
- timeout.tv_sec = Secs;
- timeout.tv_usec = 0;
- DhcpPrint(("Select: waiting for: %ld secondsn", Secs));
- Error = _I_select( 0, &SockSet, NULL, NULL, &timeout );
- if( ERROR_SUCCESS == Error ) { // timed out..
- DhcpPrint(("Recv timed out..n"));
- return ERROR_SEM_TIMEOUT;
- }
- Error = _I_recvfrom(Socket,(char *)Buffer,*BufLen, 0, &SockName, &SockNameSize);
- if( SOCKET_ERROR == Error ) {
- Error = _I_WSAGetLastError();
- DhcpPrint(("Recv failed 0x%lxn",Error));
- } else {
- *BufLen = Error;
- Error = ERROR_SUCCESS;
- *Xid = ((PDHCP_MESSAGE)Buffer)->TransactionID;
- DhcpPrint(("Recd msg XID: 0x%lx [Mdhcp? %s]n", *Xid,
- IS_MDHCP_MESSAGE(((PDHCP_MESSAGE)Buffer))?"yes":"no" ));
- }
- return Error;
- }
- VOID
- DispatchPkt( // find out any takers for Xid
- IN OUT PRECV_CTXT Ctxt, // ctxt that has buffer and buflen
- IN DWORD Xid // recd Xid
- )
- {
- do { // not a loop, just for ease of use
- LPBYTE Tmp;
- PLIST_ENTRY Entry;
- PRECV_CTXT ThisCtxt;
- Entry = DhcpGlobalRecvFromList.Flink;
- while(Entry != &DhcpGlobalRecvFromList ) {
- ThisCtxt = CONTAINING_RECORD(Entry, RECV_CTXT, RecvList);
- Entry = Entry->Flink;
- if(Xid != ThisCtxt->Xid ) continue; // mismatch.. nothing more todo
- // now check for same type of message and ctxt...
- if( (unsigned)IS_MDHCP_MESSAGE((Ctxt->Ctxt->MessageBuffer))
- !=
- IS_MDHCP_CTX( (ThisCtxt->Ctxt) )
- ) {
- //
- // The contexts dont match.. give up
- //
- continue;
- }
- //
- // check for same hardware address..
- //
- if( ThisCtxt->Ctxt->HardwareAddressLength != Ctxt->Ctxt->MessageBuffer->HardwareAddressLength ) {
- continue;
- }
- if( 0 != memcmp(ThisCtxt->Ctxt->HardwareAddress,
- Ctxt->Ctxt->MessageBuffer->HardwareAddress,
- ThisCtxt->Ctxt->HardwareAddressLength
- ) ) {
- continue;
- }
- // matched.. switch buffers to give this guy this due..
- DhcpDumpMessage(DEBUG_PROTOCOL_DUMP, (PDHCP_MESSAGE)(Ctxt->Ctxt->MessageBuffer) );
- *(ThisCtxt->BufLen) = *(Ctxt->BufLen);
- Tmp = (LPBYTE)(Ctxt->Ctxt)->MessageBuffer;
- (Ctxt->Ctxt)->MessageBuffer = (ThisCtxt->Ctxt)->MessageBuffer;
- (ThisCtxt->Ctxt)->MessageBuffer = (PDHCP_MESSAGE)Tmp;
- RemoveEntryList(&ThisCtxt->RecvList);
- InitializeListHead(&ThisCtxt->RecvList);
- DhcpAssert(FALSE == ThisCtxt->Recd);
- ThisCtxt->Recd = TRUE;
- if( 0 == SetEvent(ThisCtxt->WaitEvent) ) {
- DhcpAssert(FALSE);
- }
- break;
- }
- } while (FALSE);
- //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
- }
- DWORD
- ProcessRecvFromSocket( // wait using select and process incoming pkts
- IN OUT PRECV_CTXT Ctxt // ctxt to use
- )
- {
- time_t TimeNow;
- SOCKET Socket;
- LPBYTE Buffer;
- DWORD Xid;
- DWORD Error;
- PLIST_ENTRY Entry;
- Socket = (Ctxt->Ctxt)->Socket;
- TimeNow = time(NULL);
- Error = ERROR_SEM_TIMEOUT;
- while(TimeNow <= Ctxt->ExpTime ) { // while required to wait
- Buffer = (LPBYTE)((Ctxt->Ctxt)->MessageBuffer);
- *(Ctxt->BufLen) = Ctxt->InBufLen;
- Error = TryReceive(Socket, Buffer, Ctxt->BufLen, &Xid, (DWORD)(Ctxt->ExpTime - TimeNow));
- if( ERROR_SUCCESS != Error ) { // did not recv?
- if( WSAECONNRESET != Error ) break; // ignore possibly spurious conn-resets..
- else { TimeNow = time(NULL); continue; }
- }
- if( Xid == Ctxt->Xid ) break; // this was destined for this ctxt only..
- DispatchPkt(Ctxt, Xid);
- TimeNow = time(NULL);
- }
- if( TimeNow > Ctxt->ExpTime ) { // we timed out.
- Error = ERROR_SEM_TIMEOUT;
- }
- // now done.. so we must remove this ctxt from the list and signal first guy
- //EnterCriticalSection(&DhcpGlobalRecvFromCritSect);
- RemoveEntryList(&Ctxt->RecvList);
- CloseHandle(Ctxt->WaitEvent);
- if( !IsListEmpty(&DhcpGlobalRecvFromList)) { // ok got an elt.. signal this.
- Entry = DhcpGlobalRecvFromList.Flink;
- Ctxt = CONTAINING_RECORD(Entry, RECV_CTXT, RecvList);
- if( 0 == SetEvent(Ctxt->WaitEvent) ) {
- DhcpAssert(FALSE);
- }
- }
- //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
- return Error;
- }
- //================================================================================
- // get dhcp message with requested transaction id, but also make sure only one
- // socket is used at any given time (one socket bound to 0.0.0.0), and also
- // re-distribute message for some other thread if that is also required..
- //================================================================================
- DWORD
- GetSpecifiedDhcpMessageEx(
- IN OUT PDHCP_CONTEXT DhcpContext, // which context to recv for
- OUT PDWORD BufferLength, // how big a buffer was read?
- IN DWORD Xid, // which xid to look for?
- IN DWORD TimeToWait // how many seconds to sleep?
- )
- {
- RECV_CTXT Ctxt; // element in list for this call to getspe..
- BOOL First; // is this the first element in list?
- DWORD Result;
- Ctxt.Ctxt = DhcpContext; // fill in the context
- Ctxt.InBufLen = *BufferLength;
- Ctxt.BufLen = BufferLength;
- Ctxt.Xid = Xid;
- Ctxt.ExpTime = time(NULL) + TimeToWait;
- Ctxt.WaitEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
- Ctxt.Recd = FALSE;
- if( NULL == Ctxt.WaitEvent ) {
- DhcpAssert(NULL != Ctxt.WaitEvent);
- return GetLastError();
- }
- First = FALSE;
- InsertInPriorityList(&Ctxt, &DhcpGlobalRecvFromList, &First);
- if( First ) { // this *is* the first call to GetSpec..
- Result = ProcessRecvFromSocket(&Ctxt);
- } else { // we wait for other calls to go thru..
- Result = WaitForSingleObject(Ctxt.WaitEvent, TimeToWait * 1000);
- //EnterCriticalSection(&DhcpGlobalRecvFromCritSect);
- if( Ctxt.Recd || WAIT_FAILED == Result || WAIT_TIMEOUT == Result ) {
- if( WAIT_FAILED == Result ) Result = GetLastError();
- else if (WAIT_TIMEOUT == Result ) Result = ERROR_SEM_TIMEOUT;
- else Result = ERROR_SUCCESS;
- RemoveEntryList(&Ctxt.RecvList); // remove it from list
- //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
- CloseHandle(Ctxt.WaitEvent);
- return Result;
- } else {
- DhcpAssert(WAIT_OBJECT_0 == Result && Ctxt.Recd == FALSE );
- // have not received a packet but have been woken up? must be first in line now..
- //LeaveCriticalSection(&DhcpGlobalRecvFromCritSect);
- Result = ProcessRecvFromSocket(&Ctxt);
- }
- }
- return Result;
- }
- #define RATIO 1
- DWORD
- GetSpecifiedDhcpMessage(
- PDHCP_CONTEXT DhcpContext,
- PDWORD BufferLength,
- DWORD TransactionId,
- DWORD TimeToWait
- )
- /*++
- Routine Description:
- This function waits TimeToWait seconds to receives the specified
- DHCP response.
- Arguments:
- DhcpContext - A pointer to a DHCP context block.
- BufferLength - Returns the size of the input buffer.
- TransactionID - A filter. Wait for a message with this TID.
- TimeToWait - Time, in milli seconds, to wait for the message.
- Return Value:
- The status of the operation. If the specified message has been
- been returned, the status is ERROR_TIMEOUT.
- --*/
- {
- struct sockaddr socketName;
- int socketNameSize = sizeof( socketName );
- struct timeval timeout;
- time_t startTime, now;
- DWORD error;
- DWORD actualTimeToWait;
- SOCKET clientSocket;
- fd_set readSocketSet;
- if( !IS_ADDRESS_PLUMBED(DhcpContext) ) {
- //
- // For RAS server Lease API this call won't happen as we don't have to do this nonsense
- //
- error = GetSpecifiedDhcpMessageEx(
- DhcpContext,
- BufferLength,
- TransactionId,
- TimeToWait
- );
- if( ERROR_SUCCESS == error ) {
- // received a message frm the dhcp server..
- SERVER_REACHED(DhcpContext);
- }
- return error;
- }
- startTime = time( NULL );
- actualTimeToWait = TimeToWait;
- //
- // Setup the file descriptor set for select.
- //
- clientSocket = DhcpContext->Socket;
- FD_ZERO( &readSocketSet );
- FD_SET( clientSocket, &readSocketSet );
- while ( 1 ) {
- timeout.tv_sec = actualTimeToWait / RATIO;
- timeout.tv_usec = actualTimeToWait % RATIO;
- DhcpPrint(("Select: waiting for: %ld secondsn", actualTimeToWait));
- error = _I_select( 0, &readSocketSet, NULL, NULL, &timeout );
- if ( error == 0 ) {
- //
- // Timeout before read data is available.
- //
- DhcpPrint(("Recv timed outn", 0 ));
- error = ERROR_SEM_TIMEOUT;
- break;
- }
- error = _I_recvfrom(
- clientSocket,
- (PCHAR)DhcpContext->MessageBuffer,
- *BufferLength,
- 0,
- &socketName,
- &socketNameSize
- );
- if ( error == SOCKET_ERROR ) {
- error = _I_WSAGetLastError();
- DhcpPrint(("Recv failed, error = %ldn", error ));
- if( WSAECONNRESET != error ) break;
- //
- // ignore connreset -- this could be caused by someone sending random ICMP port unreachable.
- //
- } else if (DhcpContext->MessageBuffer->TransactionID == TransactionId ) {
- DhcpPrint(( "Received Message, XID = %lx, MDhcp = %d.n",
- TransactionId,
- IS_MDHCP_MESSAGE( DhcpContext->MessageBuffer) ));
- if (((unsigned)IS_MDHCP_MESSAGE( DhcpContext->MessageBuffer) == IS_MDHCP_CTX( DhcpContext))) {
- DhcpDumpMessage(DEBUG_PROTOCOL_DUMP, DhcpContext->MessageBuffer );
- *BufferLength = error;
- error = NO_ERROR;
- if( DhcpContext->MessageBuffer->HardwareAddressLength == DhcpContext->HardwareAddressLength
- && 0 == memcmp(DhcpContext->MessageBuffer->HardwareAddress,
- DhcpContext->HardwareAddress,
- DhcpContext->HardwareAddressLength
- )) {
- //
- // Transction IDs match, same type (MDHCP/DHCP), Hardware addresses match!
- //
- break;
- }
- }
- } else {
- DhcpPrint(( "Received a buffer with unknown XID = %lxn",
- DhcpContext->MessageBuffer->TransactionID ));
- }
- //
- // We received a message, but not the one we're interested in.
- // Reset the timeout to reflect elapsed time, and wait for
- // another message.
- //
- now = time( NULL );
- actualTimeToWait = (DWORD)(TimeToWait - RATIO * (now - startTime));
- if ( (LONG)actualTimeToWait < 0 ) {
- error = ERROR_SEM_TIMEOUT;
- break;
- }
- }
- if ( ERROR_SEM_TIMEOUT != error )
- {
- //
- // a message was received from a DHCP server. disable IP autoconfiguration.
- //
- SERVER_REACHED(DhcpContext);
- }
- return( error );
- }
- DWORD
- QueryWellKnownDnsName(
- IN OUT LPSTR lpszAutoProxyUrl,
- IN DWORD dwAutoProxyUrlLength
- )
- /*++
- Routine Description:
- This function walks a list of standard DNS names trying to find
- an entry for "wpad.some-domain-here.org" If it does, it constructs
- an URL that is suitable for use in auto-proxy.
- Arguments:
- lpszAutoProxyUrl - Url used to return a successful auto-proxy discover
- dwAutoProxyUrlLength - length of buffer passed in above
- Return Value:
- ERROR_SUCCESS - if we found a URL/DNS name
- ERROR_NOT_FOUND - on error
- revised: joshco 7-oct-1998
- if we dont get a valid domain back, be sure and try
- the netbios name ("wpad") no trailing dot.
- revised: joshco 7-oct-1998
- use the define PROXY_AUTO_DETECT_PATH instead
- of hardcoding "wpad.dat"
- --*/
- {
- #define WORK_BUFFER_SIZE 356
- DEBUG_ENTER((DBG_SOCKETS,
- Dword,
- "QueryWellKnownDnsName",
- "%x, %u",
- lpszAutoProxyUrl,
- dwAutoProxyUrlLength
- ));
- char szHostDomain[WORK_BUFFER_SIZE];
- char * pszTemp = szHostDomain ;
- char *pszDot1 = NULL;
- char *pszDot2 = NULL;
- DWORD error = ERROR_NOT_FOUND;
- DWORD dwMinDomain = 2; // By default, assume domain is of the form: .domain-name.org
- lstrcpy(szHostDomain, "wpad.");
- pszTemp += (sizeof("wpad.") - 1);
- if ( SockGetSingleValue(CONFIG_DOMAIN,
- (LPBYTE)pszTemp,
- WORK_BUFFER_SIZE - sizeof("wpad.")
- ) != ERROR_SUCCESS )
- {
- lstrcpy(szHostDomain, "wpad.");
- pszTemp = szHostDomain ;
- pszTemp += (sizeof("wpad.") - 1);
- }
- if ( (GetProxyDetectType() & PROXY_AUTO_DETECT_TYPE_NO_DOMAIN ) ||
- *pszTemp == '' )
- {
- // if the debug setting for no domain (netbios) or
- // we didnt get back a valid domain, then just do the
- // netbios name.
- // XXBUG sockgetsinglevalue returns true even if there is no domain
- INET_ASSERT(*(pszTemp - 1 ) == '.');
- *(pszTemp - 1) = '';
- }
- // Now determine which form the domain name follows:
- // domain-name.org
- // domain-name.co.uk
- pszDot1 = &szHostDomain[lstrlen(szHostDomain)-1];
- while (pszDot1 >= szHostDomain && *pszDot1 != '.')
- pszDot1--;
- // Only check .?? endings
- if (pszDot1 >= szHostDomain && (pszDot1 + 3 == &szHostDomain[lstrlen(szHostDomain)]) )
- {
- pszDot2 = pszDot1 - 1;
- while (pszDot2 >= szHostDomain && *pszDot2 != '.')
- pszDot2--;
- if (pszDot2 >= szHostDomain && pszDot2 + 3 >= pszDot1)
- {
- // Domain ended in something of the form: .co.uk
- // This requires at least 3 pieces then to be considered a domain
- dwMinDomain = 3;
- }
- else if ((pszDot2 + 4) == pszDot1)
- {
- // Check domain endings of the form ending in .com.uk
- // These special 3-letter pieces also need 3 dots to be classified
- // as a domain. Unfortunately, we can't leverage the equivalent
- // code used by cookies because there, the strings are reversed.
- static const char *s_pachSpecialDomains[] = {"COM", "EDU", "NET", "ORG", "GOV", "MIL", "INT" };
- for (int i=0; i < ARRAY_ELEMENTS(s_pachSpecialDomains); i++)
- {
- if (StrCmpNIC(pszDot2+1, s_pachSpecialDomains[i], 3) == 0)
- {
- dwMinDomain = 3;
- break;
- }
- }
- }
- }
- while (TRUE)
- {
- PHOSTENT lpHostent = _I_gethostbyname(szHostDomain);
- if ( lpHostent != NULL )
- {
- //
- // Found a host, extract the IP address and form an URL to use.
- //
- char *pszAddressStr;
- LPBYTE * addressList;
- struct in_addr sin_addr;
- DWORD dwIPAddressSize;
- addressList = (LPBYTE *)lpHostent->h_addr_list;
- *(LPDWORD)&sin_addr = *(LPDWORD)addressList[0] ;
- pszAddressStr = _I_inet_ntoa (sin_addr);
- INET_ASSERT(pszAddressStr);
- dwIPAddressSize = lstrlen(pszAddressStr);
- if ( dwAutoProxyUrlLength < (dwIPAddressSize +
- sizeof("http:///") + sizeof(PROXY_AUTO_DETECT_PATH) ) )
- {
- error = ERROR_INSUFFICIENT_BUFFER;
- goto quit;
- }
- wsprintf(lpszAutoProxyUrl, "http://%s/%s", pszAddressStr, PROXY_AUTO_DETECT_PATH );
- error = ERROR_SUCCESS;
- goto quit;
- }
- else
- {
- //
- // Did not find anything yet, reduce the domain level,
- // and if we're in the root domain stop and return error
- //
- DWORD dwPeriodCnt = 0, dwNewEndLength = 0;
- LPSTR lpszPeriod1 = NULL, lpszPeriod2 = NULL;
- for (pszTemp = szHostDomain; *pszTemp; pszTemp++ )
- {
- if ( *pszTemp == '.' ) {
- dwPeriodCnt ++;
- if ( lpszPeriod1 == NULL ) {
- lpszPeriod1 = pszTemp;
- }
- else if ( lpszPeriod2 == NULL ) {
- lpszPeriod2 = pszTemp;
- }
- }
- }
- if ( dwPeriodCnt <= dwMinDomain)
- {
- error = ERROR_NOT_FOUND;
- goto quit;
- }
- dwNewEndLength = lstrlen(lpszPeriod2);
- MoveMemory(lpszPeriod1, lpszPeriod2, dwNewEndLength);
- *(lpszPeriod1 + dwNewEndLength) = '';
- }
- }
- quit:
- DEBUG_LEAVE(error);
- return error;
- }
- //================================================================================
- // End of file
- //================================================================================