|
|
/*++
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
|