/*++ Copyright (c) 2001 Microsoft Corporation Module Name: process.c Abstract: This module contains functions to handle processing of incoming datagrams and route them to the appropriate handlers. Author: Jeffrey C. Venable, Sr. (jeffv) 01-Jun-2001 Revision History: --*/ #include "precomp.h" BOOL TftpdProcessComplete(PTFTPD_BUFFER buffer) { PTFTPD_CONTEXT context = buffer->internal.context; DWORD state; TFTPD_DEBUG((TFTPD_TRACE_PROCESS, "TftpdProcessComplete(context = %p).\n", context)); ASSERT(context->state & TFTPD_STATE_BUSY); // Reset the timer. if (!TftpdContextUpdateTimer(context)) { TftpdContextKill(context); TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED, "Out of memory"); return (FALSE); } // if (!TftpdContextUpdateTimer(context, buffer)) // Clear the busy state. do { state = context->state; if (state & TFTPD_STATE_DEAD) { if (context->type == TFTPD_WRQ) return (TRUE); return (FALSE); } } while (InterlockedCompareExchange(&context->state, (state & ~TFTPD_STATE_BUSY), state) != state); return (TRUE); } // TftpdProcessComplete() void CALLBACK TftpdProcessTimeout(PTFTPD_CONTEXT context, BOOLEAN timedOut) { PTFTPD_BUFFER buffer = NULL; LONG reference; // // The timer's reference to the context is a special case becase // the context cannot cleanup until the timer is successfully // cancelled; if we're running here, that means cleanup must wait // for us. However, if cleanup is active (TFTPD_STATE_DEAD), the // reference count might be zero; if so we just want to bail // because decrementing it back to zero causes double-delete. // do { if ((reference = context->reference) == 0) return; } while (InterlockedCompareExchange(&context->reference, reference + 1, reference) != reference); // Aquire busy-sending state. if (InterlockedCompareExchange(&context->state, TFTPD_STATE_BUSY, 0) != 0) goto exit_timer_callback; TFTPD_DEBUG((TFTPD_TRACE_PROCESS, "TftpdProcessTimeout(context = %p).\n", context)); #if defined(DBG) InterlockedIncrement((PLONG)&globals.performance.timeouts); #endif // defined(DBG) // Allocate a buffer to either retry the previous DATA/ACK we last sent, // or to send an ERROR packet if we've reached max-retries. buffer = TftpdIoAllocateBuffer(context->socket); if (buffer == NULL) goto exit_timer_callback; CopyMemory(&buffer->internal.io.peer, &context->peer, sizeof(buffer->internal.io.peer)); if (++context->retransmissions >= globals.parameters.maxRetries) { #if defined(DBG) InterlockedIncrement((PLONG)&globals.performance.drops); #endif // defined(DBG) TftpdContextKill(context); TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED, "Timeout"); goto exit_timer_callback; } buffer->internal.context = context; if (context->type == TFTPD_RRQ) buffer = TftpdReadResume(buffer); else buffer = TftpdWriteSendAck(buffer); exit_timer_callback : if (buffer != NULL) TftpdIoPostReceiveBuffer(buffer->internal.socket, buffer); TftpdContextRelease(context); } // TftpdProcessTimeout() void TftpdProcessError(PTFTPD_BUFFER buffer) { PTFTPD_CONTEXT context = NULL; context = TftpdContextAquire(&buffer->internal.io.peer); if (context == NULL) return; TFTPD_DEBUG((TFTPD_TRACE_PROCESS, "TftpdProcessError(buffer = %p, context = %p).\n", buffer, context)); TftpdContextKill(context); TftpdContextRelease(context); } // TftpdProcessError() PTFTPD_BUFFER TftpdProcessReceivedBuffer(PTFTPD_BUFFER buffer) { TFTPD_DEBUG((TFTPD_TRACE_PROCESS, "TftpdProcessReceivedBuffer(buffer = %p).\n", buffer)); buffer->message.opcode = ntohs(buffer->message.opcode); switch (buffer->message.opcode) { // // Sending files to a client: // case TFTPD_RRQ : buffer = TftpdReadRequest(buffer); break; case TFTPD_ACK : buffer->message.ack.block = ntohs(buffer->message.ack.block); buffer = TftpdReadAck(buffer); break; // // Receiving files from a client: // case TFTPD_WRQ : buffer = TftpdWriteRequest(buffer); break; case TFTPD_DATA : buffer->message.data.block = ntohs(buffer->message.data.block); buffer = TftpdWriteData(buffer); break; // // Other: // case TFTPD_ERROR : TftpdProcessError(buffer); break; default : // Just drop the packet. Somehow we received a bogus datagram // that's not TFTP protocol (possibly a broadcast). break; } // switch (buffer->message.opcode) return (buffer); } // TftpdProcessReceivedBuffer()