windows-nt/Source/XPSP1/NT/net/rras/ip/nathlp/ftp/ftpio.cpp

994 lines
31 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
ftpio.c
Abstract:
This module contains code for the FTP transparent proxy's network
I/O completion routines.
Author:
Qiang Wang (qiangw) 10-Apr-2000
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "ftpmsg.h"
VOID
FtpAcceptCompletionRoutine(
ULONG ErrorCode,
ULONG BytesTransferred,
PNH_BUFFER Bufferp
)
/*++
Routine Description:
This routine is invoked upon completion of an accept operation
on a FTP transparent proxy stream socket.
Arguments:
ErrorCode - Win32 status code for the I/O operation
BytesTransferred - number of bytes in 'Bufferp'
Bufferp - holds the local and remote IP address and port
for the connection.
Return Value:
none.
Environment:
Runs in the context of a worker-thread which has just dequeued
an I/O completion packet from the common I/O completion port
with which our stream sockets are associated.
A reference to the component will have been made on our behalf
by 'NhAcceptStreamSocket'.
A reference to the interface will have been made on our behalf
by whoever issued the I/O request.
--*/
{
SOCKET AcceptedSocket;
PFTP_CONNECTION Connectionp;
ULONG Error;
PFTP_INTERFACE Interfacep;
SOCKET ListeningSocket;
PROFILE("FtpAcceptCompletionRoutine");
do {
AcceptedSocket = (SOCKET)Bufferp->Socket;
Interfacep = (PFTP_INTERFACE)Bufferp->Context;
ListeningSocket = (SOCKET)Bufferp->Context2;
//
// Acquire three additional references to the interface
// for the followup requests that we will issue below,
// and lock the interface.
//
EnterCriticalSection(&FtpInterfaceLock);
if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
LeaveCriticalSection(&FtpInterfaceLock);
NhReleaseBuffer(Bufferp);
NhDeleteStreamSocket(AcceptedSocket);
break;
}
FTP_REFERENCE_INTERFACE(Interfacep);
FTP_REFERENCE_INTERFACE(Interfacep);
LeaveCriticalSection(&FtpInterfaceLock);
ACQUIRE_LOCK(Interfacep);
//
// Process the accept-completion.
// First look for an error code. If an error occurred
// and the interface is no longer active, end the completion-handling.
// Otherwise, attempt to reissue the accept-request.
//
if (ErrorCode) {
NhTrace(
TRACE_FLAG_IO,
"FtpAcceptCompletionRoutine: error %d for interface %d",
ErrorCode, Interfacep->Index
);
//
// See if the interface is still active and, if so, reissue
// the accept-request. Since we will not be creating an active
// endpoint, we won't need the second reference to the interface.
//
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
if (!FTP_INTERFACE_ACTIVE(Interfacep)) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhDeleteStreamSocket(AcceptedSocket);
} else {
//
// Reissue the accept-request. Note that the callee is now
// responsible for the reference we made to the interface.
//
Error =
FtpAcceptConnectionInterface(
Interfacep,
ListeningSocket,
AcceptedSocket,
Bufferp,
NULL
);
RELEASE_LOCK(Interfacep);
if (Error) {
NhReleaseBuffer(Bufferp);
NhDeleteStreamSocket(AcceptedSocket);
NhTrace(
TRACE_FLAG_IO,
"FtpAcceptCompletionRoutine: error %d reissuing accept",
Error
);
}
}
break;
}
//
// Now see if the interface is operational.
// If it isn't, we need to destroy the accepted socket
// and return control.
//
if (!FTP_INTERFACE_ACTIVE(Interfacep)) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhDeleteStreamSocket(AcceptedSocket);
NhTrace(
TRACE_FLAG_IO,
"FtpAcceptCompletionRoutine: interface %d inactive",
Interfacep->Index
);
InterlockedIncrement(
reinterpret_cast<LPLONG>(&FtpStatistics.ConnectionsDropped)
);
break;
}
//
// We now create a 'FTP_CONNECTION' for the new connection,
// in the process launching operations for the connection.
// The connection management module will handle the accepted socket
// from here onward, and is responsible for the references to the
// interface that were made above.
//
NhTrace(
TRACE_FLAG_IO,
"FtpAcceptCompletionRoutine: socket %d accepting connection",
ListeningSocket
);
Error =
FtpCreateConnection(
Interfacep,
ListeningSocket,
AcceptedSocket,
Bufferp->Buffer,
&Connectionp
);
if (Error) {
InterlockedIncrement(
reinterpret_cast<LPLONG>(&FtpStatistics.ConnectionsDropped)
);
} else {
InterlockedIncrement(
reinterpret_cast<LPLONG>(&FtpStatistics.ConnectionsAccepted)
);
}
//
// Finally, issue an accept operation for the next connection-request
// on the listening socket. Note that the callee is responsible
// for releasing the reference to the interface in case of a failure.
//
Error =
FtpAcceptConnectionInterface(
Interfacep,
ListeningSocket,
INVALID_SOCKET,
Bufferp,
NULL
);
RELEASE_LOCK(Interfacep);
if (Error) { NhReleaseBuffer(Bufferp); }
} while(FALSE);
FTP_DEREFERENCE_INTERFACE(Interfacep);
DEREFERENCE_FTP();
} // FtpAcceptCompletionRoutine
VOID
FtpCloseEndpointNotificationRoutine(
ULONG ErrorCode,
ULONG BytesTransferred,
PNH_BUFFER Bufferp
)
/*++
Routine Description:
This routine is invoked upon notification of a close operation
on a FTP transparent proxy stream socket.
Arguments:
ErrorCode - Win32 status code for the I/O operation
BytesTransferred - number of bytes in 'Bufferp'
Bufferp - holds context information for the closed socket.
Note that we are not allowed to release this buffer here.
Return Value:
none.
Environment:
Runs in the context of a wait-thread.
A reference to the component will have been made on our behalf
by 'NhAcceptStreamSocket' or 'NhConnectStreamSocket'.
A reference to the interface will have been made on our behalf
by whoever issued the I/O request.
Both of these references are released here.
--*/
{
SOCKET ClosedSocket;
ULONG EndpointId;
PFTP_INTERFACE Interfacep;
PROFILE("FtpCloseEndpointNotificationRoutine");
do {
ClosedSocket = (SOCKET)Bufferp->Socket;
Interfacep = (PFTP_INTERFACE)Bufferp->Context;
EndpointId = PtrToUlong(Bufferp->Context2);
NhTrace(
TRACE_FLAG_IO,
"FtpCloseEndpointNotificationRoutine: endpoint %d socket %d "
"closed, error %d",
EndpointId, ClosedSocket, ErrorCode
);
#if 0
PFTP_ENDPOINT Endpointp;
//
// Lock the interface, and retrieve the endpoint whose socket has
// been closed.
//
ACQUIRE_LOCK(Interfacep);
Endpointp = FtpLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
if (Endpointp) {
FtpCloseActiveEndpoint(Endpointp, ClosedSocket);
}
RELEASE_LOCK(Interfacep);
#endif
} while(FALSE);
FTP_DEREFERENCE_INTERFACE(Interfacep);
DEREFERENCE_FTP();
} // FtpCloseEndpointNotificationRoutine
VOID
FtpConnectEndpointCompletionRoutine(
ULONG ErrorCode,
ULONG BytesTransferred,
PNH_BUFFER Bufferp
)
/*++
Routine Description:
This routine is invoked upon completion of a connect operation
on a FTP transparent proxy stream socket.
Arguments:
ErrorCode - Win32 status code for the I/O operation
BytesTransferred - number of bytes in 'Bufferp'
Bufferp - holds the context information for the endpoint.
Note that we are not allowed to release this buffer here.
Return Value:
none.
Environment:
Runs in the context of a wait-thread.
A reference to the component will have been made on our behalf
by 'NhConnectStreamSocket'.
A reference to the interface will have been made on our behalf
by whoever issued the I/O request.
Neither of these references may be released here; they are both
released in the close-notification routine, which we are guaranteed
will be invoked. (Eventually.)
--*/
{
SOCKET ConnectedSocket;
ULONG EndpointId;
PFTP_ENDPOINT Endpointp;
ULONG Error;
PFTP_INTERFACE Interfacep;
PROFILE("FtpConnectEndpointCompletionRoutine");
do {
ConnectedSocket = (SOCKET)Bufferp->Socket;
Interfacep = (PFTP_INTERFACE)Bufferp->Context;
EndpointId = PtrToUlong(Bufferp->Context2);
//
// Acquire two additional references to the interface
// for the endpoint-activation that we will initiate below,
// lock the interface, and retrieve the endpoint.
//
EnterCriticalSection(&FtpInterfaceLock);
if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
LeaveCriticalSection(&FtpInterfaceLock);
break;
}
FTP_REFERENCE_INTERFACE(Interfacep);
LeaveCriticalSection(&FtpInterfaceLock);
ACQUIRE_LOCK(Interfacep);
Endpointp = FtpLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
//
// First look for an error code.
// If an error occurred and the interface is still active,
// destroy the endpoint.
// If the interface is inactive, we're done, since the endpoint
// will have already been destroyed.
// If the interface is active but the endpoint has already
// been destroyed, end this connection-attempt.
//
if (ErrorCode) {
if (Endpointp) {
NhTrace(
TRACE_FLAG_IO,
"FtpConnectEndpointCompletionRoutine: deleting endpoint %d "
"on error %d", EndpointId, ErrorCode
);
FtpDeleteActiveEndpoint(Endpointp);
}
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
break;
} else if (!FTP_INTERFACE_ACTIVE(Interfacep)) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpConnectEndpointCompletionRoutine: interface %d inactive",
Interfacep->Index
);
break;
} else if (!Endpointp) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpConnectEndpointCompletionRoutine: endpoint %d removed",
EndpointId
);
break;
}
//
// We now activate the endpoint, beginning data transfer.
// Note that it is the caller's responsibility to release
// the two new references to the interface if an error occurs.
//
NhTrace(
TRACE_FLAG_IO,
"FtpConnectEndpointCompletionRoutine: endpoint %d socket %d "
"connected", EndpointId, ConnectedSocket
);
Error = FtpActivateActiveEndpoint(Interfacep, Endpointp);
RELEASE_LOCK(Interfacep);
} while(FALSE);
} // FtpConnectEndpointCompletionRoutine
VOID
FtpReadEndpointCompletionRoutine(
ULONG ErrorCode,
ULONG BytesTransferred,
PNH_BUFFER Bufferp
)
/*++
Routine Description:
This routine is invoked upon completion of a read operation
on a FTP transparent proxy stream socket.
The contexts for all reads are the interface and endpoint-identifier
corresponding to the socket, stored in 'Context' and 'Context2',
respectively.
Arguments:
ErrorCode - Win32 status code for the I/O operation
BytesTransferred - number of bytes in 'Bufferp'
Bufferp - holds data read from the socket
Return Value:
none.
Environment:
Runs in the context of a worker-thread which has just dequeued an
I/O completion packet from the common I/O completion port with which
our stream sockets are associated.
A reference to the component will have been made on our behalf
by 'NhReadStreamSocket'.
A reference to the interface will have been made on our behalf
by whoever issued the I/O request.
--*/
{
ULONG EndpointId;
PFTP_ENDPOINT Endpointp;
ULONG Error;
PFTP_INTERFACE Interfacep;
PROFILE("FtpReadEndpointCompletionRoutine");
do {
Interfacep = (PFTP_INTERFACE)Bufferp->Context;
EndpointId = PtrToUlong(Bufferp->Context2);
//
// Acquire two additional references to the interface
// for the followup requests that we will issue below,
// lock the interface, and retrieve the endpoint.
//
EnterCriticalSection(&FtpInterfaceLock);
if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
LeaveCriticalSection(&FtpInterfaceLock);
NhReleaseBuffer(Bufferp);
break;
}
FTP_REFERENCE_INTERFACE(Interfacep);
LeaveCriticalSection(&FtpInterfaceLock);
ACQUIRE_LOCK(Interfacep);
Endpointp = FtpLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
//
// Process the read-completion. First we look for an error-code,
// and if we find one, we decide whether to re-issue the read-request.
// If the interface is still active, the error-code is non-fatal, and
// the endpoint still exists, we reissue the read.
//
if (ErrorCode) {
//
// We won't be needing the second reference to the interface,
// since we won't be calling 'FtpProcessMessage.
//
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: error %d for endpoint %d",
ErrorCode, EndpointId
);
if (!FTP_INTERFACE_ACTIVE(Interfacep) || !Endpointp) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
} else if (NhIsFatalSocketError(ErrorCode)) {
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: deleting endpoint %d "
"on fatal read-error %d", EndpointId, ErrorCode
);
} else {
//
// We need to repost the buffer for another read operation,
// so we now reissue a read for the same number of bytes as
// before.
//
Error =
NhReadStreamSocket(
&FtpComponentReference,
Bufferp->Socket,
Bufferp,
Bufferp->BytesToTransfer,
Bufferp->TransferOffset,
FtpReadEndpointCompletionRoutine,
Bufferp->Context,
Bufferp->Context2
);
if (Error) {
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: deleting endpoint "
"%d, NhReadStreamSocket=%d", EndpointId, Error
);
if (Error != ERROR_NETNAME_DELETED) {
NhWarningLog(
IP_FTP_LOG_RECEIVE_FAILED,
Error,
"%I",
NhQueryAddressSocket(Bufferp->Socket)
);
}
NhReleaseBuffer(Bufferp);
break;
}
RELEASE_LOCK(Interfacep);
}
break;
} else if (!BytesTransferred) {
//
// Zero bytes were read from the endpoint's socket.
// This indicates that the sender has closed the socket.
// We now propagate the closure to the alternate socket
// for the endpoint. When the 'other' sender is done,
// this endpoint will be removed altogether.
//
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: endpoint %d socket %d "
"closed", EndpointId, Bufferp->Socket
);
if (Endpointp) {
FtpCloseActiveEndpoint(Endpointp, Bufferp->Socket);
}
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
break;
}
//
// The original request completed successfully.
// Now see if the interface and endpoint are operational and,
// if not, return control.
//
if (!FTP_INTERFACE_ACTIVE(Interfacep)) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: interface %d inactive",
Interfacep->Index
);
break;
} else if (!Endpointp) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: endpoint %d not found",
EndpointId
);
break;
}
//
// Record the number of bytes read, and issue a read-request
// for the remainder if necessary. Otherwise, process the completed
// message.
//
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: endpoint %d socket %d read %d "
"bytes", EndpointId, Bufferp->Socket, BytesTransferred
);
ASSERT(BytesTransferred <= Bufferp->BytesToTransfer);
Bufferp->BytesToTransfer -= BytesTransferred;
Bufferp->TransferOffset += BytesTransferred;
if (Bufferp->BytesToTransfer > 0 &&
FtpIsFullMessage(
reinterpret_cast<CHAR*>(Bufferp->Buffer),
Bufferp->TransferOffset
) == NULL) {
//
// Read the remainder of the message, after releasing
// the second reference to the interface, which is needed
// only when we call 'FtpProcessMessage'.
//
FTP_DEREFERENCE_INTERFACE(Interfacep);
Error =
NhReadStreamSocket(
&FtpComponentReference,
Bufferp->Socket,
Bufferp,
Bufferp->BytesToTransfer,
Bufferp->TransferOffset,
FtpReadEndpointCompletionRoutine,
Bufferp->Context,
Bufferp->Context2
);
if (Error) {
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpReadEndpointCompletionRoutine: deleting endpoint "
"%d, NhReadStreamSocket=%d", EndpointId, Error
);
if (Error != ERROR_NETNAME_DELETED) {
NhWarningLog(
IP_FTP_LOG_RECEIVE_FAILED,
Error,
"%I",
NhQueryAddressSocket(Bufferp->Socket)
);
}
NhReleaseBuffer(Bufferp);
break;
}
} else {
//
// We've finished reading something. Process it.
//
FtpProcessMessage(Interfacep, Endpointp, Bufferp);
}
RELEASE_LOCK(Interfacep);
} while(FALSE);
FTP_DEREFERENCE_INTERFACE(Interfacep);
DEREFERENCE_FTP();
} // FtpReadEndpointCompletionRoutine
VOID
FtpWriteEndpointCompletionRoutine(
ULONG ErrorCode,
ULONG BytesTransferred,
PNH_BUFFER Bufferp
)
/*++
Routine Description:
This routine is invoked upon completion of a write-operation
on a stream socket for a FTP control-channel connection.
The contexts for all writes are the interface and endpoint-identifier
corresponding to the socket, stored in 'Context' and 'Context2',
respectively.
Arguments:
ErrorCode - Win32 status code for the I/O operation
BytesTransferred - number of bytes in 'Bufferp'
Bufferp - holds data read from the stream socket
Return Value:
none.
Environment:
Runs in the context of a worker-thread which has just dequeued an
I/O completion packet from the common I/O completion port with which our
stream sockets are associated.
A reference to the component will have been made on our behalf
by 'NhWriteStreamSocket'.
A reference to the interface will have been made on our behalf
by whoever issued the I/O request.
--*/
{
ULONG Error;
ULONG EndpointId;
PFTP_ENDPOINT Endpointp;
PFTP_INTERFACE Interfacep;
PROFILE("FtpWriteEndpointCompletionRoutine");
do {
Interfacep = (PFTP_INTERFACE)Bufferp->Context;
EndpointId = PtrToUlong(Bufferp->Context2);
//
// Acquire an additional reference to the interface
// for the followup requests that we will issue below,
// lock the interface, and retrieve the endpoint.
//
EnterCriticalSection(&FtpInterfaceLock);
if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
LeaveCriticalSection(&FtpInterfaceLock);
NhReleaseBuffer(Bufferp);
break;
}
LeaveCriticalSection(&FtpInterfaceLock);
ACQUIRE_LOCK(Interfacep);
Endpointp = FtpLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
//
// Process the write-completion. First we look for an error-code,
// and if we find one, we decide whether to re-issue the write-request.
// If the interface is still active, the error-code is non-fatal, and
// the endpoint still exists, we reissue the write.
//
if (ErrorCode) {
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: error %d for endpoint %d",
ErrorCode, EndpointId
);
if (!FTP_INTERFACE_ACTIVE(Interfacep) || !Endpointp) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
} else if (NhIsFatalSocketError(ErrorCode)) {
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: deleting endpoint %d "
"on fatal write-error %d", EndpointId, ErrorCode
);
} else {
//
// We need to repost the buffer for another write operation,
// so we now reissue a write for the same number of bytes
// as before.
//
Error =
NhWriteStreamSocket(
&FtpComponentReference,
Bufferp->Socket,
Bufferp,
Bufferp->BytesToTransfer,
Bufferp->TransferOffset,
FtpWriteEndpointCompletionRoutine,
Bufferp->Context,
Bufferp->Context2
);
if (Error) {
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: deleting endpoint "
"%d, NhWriteStreamSocket=%d", EndpointId, Error
);
NhWarningLog(
IP_FTP_LOG_SEND_FAILED,
Error,
"%I",
NhQueryAddressSocket(Bufferp->Socket)
);
NhReleaseBuffer(Bufferp);
break;
}
RELEASE_LOCK(Interfacep);
}
break;
}
//
// The original request completed successfully.
// Now see if the interface and endpoint are operational and,
// if not, return control.
//
if (!FTP_INTERFACE_ACTIVE(Interfacep)) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: interface %d inactive",
Interfacep->Index
);
break;
} else if (!Endpointp) {
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhReleaseBuffer(Bufferp);
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: endpoint %d not found",
EndpointId
);
break;
}
//
// Record the number of bytes written, and issue a write-request
// for the remainder if necessary. Otherwise, we are done,
// and we return to reading from the 'other' socket for the
// control-channel.
//
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: endpoint %d socket %d wrote %d "
"bytes", EndpointId, Bufferp->Socket, BytesTransferred
);
ASSERT(BytesTransferred <= Bufferp->BytesToTransfer);
Bufferp->BytesToTransfer -= BytesTransferred;
Bufferp->TransferOffset += BytesTransferred;
if (Bufferp->BytesToTransfer) {
//
// Write the remainder of the message
//
Error =
NhWriteStreamSocket(
&FtpComponentReference,
Bufferp->Socket,
Bufferp,
Bufferp->BytesToTransfer,
Bufferp->TransferOffset,
FtpWriteEndpointCompletionRoutine,
Bufferp->Context,
Bufferp->Context2
);
if (Error) {
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
FTP_DEREFERENCE_INTERFACE(Interfacep);
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: deleting endpoint %d, "
"NhWriteStreamSocket=%d", EndpointId, Error
);
NhWarningLog(
IP_FTP_LOG_SEND_FAILED,
Error,
"%I",
NhQueryAddressSocket(Bufferp->Socket)
);
NhReleaseBuffer(Bufferp);
break;
}
} else {
SOCKET Socket;
ULONG UserFlags;
//
// We now go back to reading from the other socket of the
// endpoint, by issuing the next read on the endpoint's other
// socket. Note that it is the responsibility of the callee
// to release the reference to the interface if a failure occurs.
//
UserFlags = Bufferp->UserFlags;
if (UserFlags & FTP_BUFFER_FLAG_FROM_ACTUAL_CLIENT) {
Socket = Endpointp->HostSocket;
UserFlags &= ~(ULONG)FTP_BUFFER_FLAG_CONTINUATION;
UserFlags |= FTP_BUFFER_FLAG_FROM_ACTUAL_CLIENT;
} else {
Socket = Endpointp->ClientSocket;
UserFlags &= ~(ULONG)FTP_BUFFER_FLAG_CONTINUATION;
UserFlags |= FTP_BUFFER_FLAG_FROM_ACTUAL_HOST;
}
NhReleaseBuffer(Bufferp);
Error =
FtpReadActiveEndpoint(
Interfacep,
Endpointp,
Socket,
UserFlags
);
if (Error) {
NhTrace(
TRACE_FLAG_IO,
"FtpWriteEndpointCompletionRoutine: deleting endpoint %d, "
"FtpReadActiveEndpoint=%d", EndpointId, Error
);
FtpDeleteActiveEndpoint(Endpointp);
RELEASE_LOCK(Interfacep);
NhWarningLog(
IP_FTP_LOG_RECEIVE_FAILED,
Error,
"%I",
NhQueryAddressSocket(Socket)
);
break;
}
}
RELEASE_LOCK(Interfacep);
} while(FALSE);
FTP_DEREFERENCE_INTERFACE(Interfacep);
DEREFERENCE_FTP();
} // FtpWriteEndpointCompletionRoutine