343 lines
9 KiB
C++
343 lines
9 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998, Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dnsio.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code for the DNS allocator's network I/O completion
|
||
routines.
|
||
|
||
Author:
|
||
|
||
Abolade Gbadegesin (aboladeg) 9-Mar-1998
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#include "dnsmsg.h"
|
||
|
||
|
||
VOID
|
||
DnsReadCompletionRoutine(
|
||
ULONG ErrorCode,
|
||
ULONG BytesTransferred,
|
||
PNH_BUFFER Bufferp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked upon completion of a read operation
|
||
on a datagram socket bound to the DNS server UDP port.
|
||
|
||
The message read is validated and processed; the processing may involve
|
||
creating a query-record and forwarding the query to a server, or
|
||
matching a response to an existing query-record and forwarding the
|
||
response to the appropriate client.
|
||
|
||
Arguments:
|
||
|
||
ErrorCode - Win32 status code for the I/O operation
|
||
|
||
BytesTransferred - number of bytes in 'Bufferp'
|
||
|
||
Bufferp - holds data read from the datagram socket
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Runs in the context of an RTUTILS.DLL worker-thread which has just
|
||
dequeued an I/O completion packet from the common I/O completion port
|
||
with which our datagram sockets are associated.
|
||
A reference to the component will have been made on our behalf
|
||
by 'NhReadDatagramSocket'.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Error;
|
||
PDNS_HEADER Headerp;
|
||
PDNS_INTERFACE Interfacep;
|
||
|
||
PROFILE("DnsReadCompletionRoutine");
|
||
|
||
do {
|
||
|
||
//
|
||
// There are two cases where we don't process the message;
|
||
// (a) the I/O operation failed
|
||
// (b) the interface is no longer active
|
||
// In case (a), we repost the buffer; in case (b), we do not.
|
||
//
|
||
|
||
Interfacep = (PDNS_INTERFACE)Bufferp->Context;
|
||
|
||
//
|
||
// First look for an error code
|
||
//
|
||
|
||
if (ErrorCode) {
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_IO,
|
||
"DnsReadCompletionRoutine: error %d for read-context %x",
|
||
ErrorCode,
|
||
Bufferp->Context
|
||
);
|
||
|
||
//
|
||
// See if the interface is still active
|
||
//
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
if (!DNS_INTERFACE_ACTIVE(Interfacep)) {
|
||
RELEASE_LOCK(Interfacep);
|
||
NhReleaseBuffer(Bufferp);
|
||
} else {
|
||
RELEASE_LOCK(Interfacep);
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
NhReleaseBuffer(Bufferp);
|
||
} else {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
//
|
||
// Repost the buffer for another read operation
|
||
//
|
||
do {
|
||
Error =
|
||
NhReadDatagramSocket(
|
||
&DnsComponentReference,
|
||
Bufferp->Socket,
|
||
Bufferp,
|
||
DnsReadCompletionRoutine,
|
||
Bufferp->Context,
|
||
Bufferp->Context2
|
||
);
|
||
//
|
||
// A connection-reset error indicates that our last
|
||
// *send* could not be delivered at its destination.
|
||
// We could hardly care less; so issue the read again,
|
||
// immediately.
|
||
//
|
||
} while (Error == WSAECONNRESET);
|
||
if (Error) {
|
||
ACQUIRE_LOCK(Interfacep);
|
||
DnsDeferReadInterface(Interfacep, Bufferp->Socket);
|
||
RELEASE_LOCK(Interfacep);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhWarningLog(
|
||
IP_DNS_PROXY_LOG_RECEIVE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
NhReleaseBuffer(Bufferp);
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Now see if the interface is operational
|
||
//
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
if (!DNS_INTERFACE_ACTIVE(Interfacep)) {
|
||
RELEASE_LOCK(Interfacep);
|
||
NhReleaseBuffer(Bufferp);
|
||
NhTrace(
|
||
TRACE_FLAG_IO,
|
||
"DnsReadCompletionRoutine: interface %d inactive",
|
||
Interfacep->Index
|
||
);
|
||
break;
|
||
}
|
||
RELEASE_LOCK(Interfacep);
|
||
|
||
//
|
||
// Now look at the message
|
||
//
|
||
|
||
Headerp = (PDNS_HEADER)Bufferp->Buffer;
|
||
|
||
if (Headerp->IsResponse == DNS_MESSAGE_QUERY) {
|
||
DnsProcessQueryMessage(
|
||
Interfacep,
|
||
Bufferp
|
||
);
|
||
} else {
|
||
DnsProcessResponseMessage(
|
||
Interfacep,
|
||
Bufferp
|
||
);
|
||
}
|
||
|
||
} while(FALSE);
|
||
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
DEREFERENCE_DNS();
|
||
|
||
} // DnsReadCompletionRoutine
|
||
|
||
|
||
VOID
|
||
DnsWriteCompletionRoutine(
|
||
ULONG ErrorCode,
|
||
ULONG BytesTransferred,
|
||
PNH_BUFFER Bufferp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked upon completion of a write-operation
|
||
on a datagram socket bound to the DNS server UDP port.
|
||
|
||
The write-context for all writes is a 'DNS_QUERY'. Our handling
|
||
is dependent on whether the message written was a query or a response.
|
||
|
||
Upon completion of a query, we may need to do a resend if there was
|
||
an error. Upon completion of a response, we delete the query-record.
|
||
|
||
Arguments:
|
||
|
||
ErrorCode - Win32 status code for the I/O operation
|
||
|
||
BytesTransferred - number of bytes in 'Bufferp'
|
||
|
||
Bufferp - holds data read from the datagram socket
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Runs in the context of an RTUTILS.DLL worker-thread which has just
|
||
dequeued an I/O completion packet from the common I/O completion port
|
||
with which our datagram sockets are associated.
|
||
A reference to the component will have been made on our behalf
|
||
by 'NhReadDatagramSocket'.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Error;
|
||
PDNS_HEADER Headerp;
|
||
PDNS_INTERFACE Interfacep;
|
||
USHORT QueryId;
|
||
PDNS_QUERY Queryp;
|
||
PULONG Server;
|
||
|
||
PROFILE("DnsWriteCompletionRoutine");
|
||
|
||
Interfacep = (PDNS_INTERFACE)Bufferp->Context;
|
||
QueryId = (USHORT)Bufferp->Context2;
|
||
Headerp = (PDNS_HEADER)Bufferp->Buffer;
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
|
||
//
|
||
// Obtain the query associated with the send.
|
||
//
|
||
|
||
Queryp = DnsMapResponseToQuery(Interfacep, QueryId);
|
||
|
||
if (Headerp->IsResponse == DNS_MESSAGE_RESPONSE) {
|
||
|
||
if (ErrorCode) {
|
||
|
||
//
|
||
// An error occurred sending the message to the client
|
||
//
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsWriteCompletionRoutine: error %d response %d interface %d",
|
||
ErrorCode,
|
||
Queryp ? Queryp->QueryId : -1,
|
||
Interfacep->Index
|
||
);
|
||
NhWarningLog(
|
||
IP_DNS_PROXY_LOG_RESPONSE_FAILED,
|
||
ErrorCode,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
|
||
} else if (Queryp && Headerp->ResponseCode == DNS_RCODE_NOERROR) {
|
||
|
||
//
|
||
// We're done with this query since it succeeded; remove it.
|
||
//
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsWriteCompletionRoutine: removing query %d interface %d",
|
||
Queryp->QueryId,
|
||
Interfacep->Index
|
||
);
|
||
|
||
DnsDeleteQuery(Interfacep, Queryp);
|
||
}
|
||
} else {
|
||
|
||
if (!ErrorCode) {
|
||
|
||
//
|
||
// No errors, so just return.
|
||
//
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsWriteCompletionRoutine: sent query %d interface %d",
|
||
Queryp ? Queryp->QueryId : -1,
|
||
Interfacep->Index
|
||
);
|
||
} else {
|
||
|
||
//
|
||
// The query just went out and it failed.
|
||
//
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsWriteCompletionRoutine: error %d for query %d interface %d",
|
||
ErrorCode,
|
||
Queryp ? Queryp->QueryId : -1,
|
||
Interfacep->Index
|
||
);
|
||
NhWarningLog(
|
||
IP_DNS_PROXY_LOG_QUERY_FAILED,
|
||
ErrorCode,
|
||
"%I%I%I",
|
||
Queryp ? Queryp->SourceAddress : -1,
|
||
Bufferp->WriteAddress.sin_addr.s_addr,
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
}
|
||
}
|
||
|
||
RELEASE_LOCK(Interfacep);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhReleaseBuffer(Bufferp);
|
||
DEREFERENCE_DNS();
|
||
|
||
} // DnsWriteCompletionRoutine
|
||
|