Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tftp_server.c Source File

tftp_server.c

Go to the documentation of this file.
00001 /**
00002  * @file tftp_server.c
00003  * @brief TFTP server
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * TFTP is a very simple protocol used to transfer files. Refer to the
00028  * following RFCs for complete details:
00029  * - RFC 1123:  Requirements for Internet Hosts
00030  * - RFC 1350: The TFTP Protocol (Revision 2)
00031  * - RFC 1782: TFTP Option Extension
00032  * - RFC 1783: TFTP Blocksize Option
00033  * - RFC 1784: TFTP Timeout Interval and Transfer Size Options
00034  *
00035  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00036  * @version 1.7.6
00037  **/
00038 
00039 //Switch to the appropriate trace level
00040 #define TRACE_LEVEL TFTP_TRACE_LEVEL
00041 
00042 //Dependencies
00043 #include "tftp/tftp_server.h"
00044 #include "debug.h"
00045 
00046 //Check TCP/IP stack configuration
00047 #if (TFTP_SERVER_SUPPORT == ENABLED)
00048 
00049 
00050 /**
00051  * @brief Initialize settings with default values
00052  * @param[out] settings Structure that contains TFTP server settings
00053  **/
00054 
00055 void tftpServerGetDefaultSettings(TftpServerSettings *settings)
00056 {
00057    //The TFTP server is not bound to any interface
00058    settings->interface = NULL;
00059 
00060    //TFTP port number
00061    settings->port = TFTP_PORT;
00062 
00063    //Open file callback function
00064    settings->openFileCallback = NULL;
00065    //Write file callback function
00066    settings->writeFileCallback = NULL;
00067    //Read file callback function
00068    settings->readFileCallback = NULL;
00069    //Close file callback function
00070    settings->closeFileCallback = NULL;
00071 }
00072 
00073 
00074 /**
00075  * @brief TFTP server initialization
00076  * @param[in] context Pointer to the TFTP server context
00077  * @param[in] settings TFTP server specific settings
00078  * @return Error code
00079  **/
00080 
00081 error_t tftpServerInit(TftpServerContext *context, const TftpServerSettings *settings)
00082 {
00083    error_t error;
00084 
00085    //Debug message
00086    TRACE_INFO("Initializing TFTP server...\r\n");
00087 
00088    //Ensure the parameters are valid
00089    if(context == NULL || settings == NULL)
00090       return ERROR_INVALID_PARAMETER;
00091 
00092    //Clear the TFTP server context
00093    memset(context, 0, sizeof(TftpServerContext));
00094 
00095    //Save user settings
00096    context->settings = *settings;
00097 
00098    //Create an event object to poll the state of sockets
00099    if(!osCreateEvent(&context->event))
00100    {
00101       //Failed to create event
00102       return ERROR_OUT_OF_RESOURCES;
00103    }
00104 
00105    //Start of exception handling block
00106    do
00107    {
00108       //Open a UDP socket
00109       context->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
00110 
00111       //Failed to open socket?
00112       if(context->socket == NULL)
00113       {
00114          //Report an error
00115          error = ERROR_OPEN_FAILED;
00116          //Exit immediately
00117          break;
00118       }
00119 
00120       //Associate the socket with the relevant interface
00121       error = socketBindToInterface(context->socket, settings->interface);
00122       //Unable to bind the socket to the desired interface?
00123       if(error)
00124          break;
00125 
00126       //The TFTP server listens for connection requests on port 69
00127       error = socketBind(context->socket, &IP_ADDR_ANY, settings->port);
00128       //Unable to bind the socket to the desired port?
00129       if(error)
00130          break;
00131 
00132       //End of exception handling block
00133    } while(0);
00134 
00135    //Did we encounter an error?
00136    if(error)
00137    {
00138       //Free previously allocated resources
00139       osDeleteEvent(&context->event);
00140       //Close socket
00141       socketClose(context->socket);
00142    }
00143 
00144    //Return status code
00145    return error;
00146 }
00147 
00148 
00149 /**
00150  * @brief Start TFTP server
00151  * @param[in] context Pointer to the TFTP server context
00152  * @return Error code
00153  **/
00154 
00155 error_t tftpServerStart(TftpServerContext *context)
00156 {
00157    OsTask *task;
00158 
00159    //Debug message
00160    TRACE_INFO("Starting TFTP server...\r\n");
00161 
00162    //Make sure the TFTP server context is valid
00163    if(context == NULL)
00164       return ERROR_INVALID_PARAMETER;
00165 
00166    //Create the TFTP server task
00167    task = osCreateTask("TFTP Server", (OsTaskCode) tftpServerTask,
00168       context, TFTP_SERVER_STACK_SIZE, TFTP_SERVER_PRIORITY);
00169 
00170    //Unable to create the task?
00171    if(task == OS_INVALID_HANDLE)
00172       return ERROR_OUT_OF_RESOURCES;
00173 
00174    //Successful processing
00175    return NO_ERROR;
00176 }
00177 
00178 
00179 /**
00180  * @brief TFTP server task
00181  * @param[in] context Pointer to the TFTP server context
00182  **/
00183 
00184 void tftpServerTask(TftpServerContext *context)
00185 {
00186    error_t error;
00187    uint_t i;
00188    TftpClientConnection *connection;
00189 
00190 #if (NET_RTOS_SUPPORT == ENABLED)
00191    //Process events
00192    while(1)
00193    {
00194 #endif
00195       //Clear event descriptor set
00196       memset(context->eventDesc, 0, sizeof(context->eventDesc));
00197 
00198       //Specify the events the application is interested in
00199       for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
00200       {
00201          //Point to the structure describing the current connection
00202          connection = &context->connection[i];
00203 
00204          //Loop through active connections only
00205          if(connection->state != TFTP_STATE_CLOSED)
00206          {
00207             //Wait for a packet to be received
00208             context->eventDesc[i].socket = connection->socket;
00209             context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY;
00210          }
00211       }
00212 
00213       //The TFTP server listens for connection requests on port 69
00214       context->eventDesc[i].socket = context->socket;
00215       context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY;
00216 
00217       //Wait for one of the set of sockets to become ready to perform I/O
00218       error = socketPoll(context->eventDesc, TFTP_SERVER_MAX_CONNECTIONS + 1,
00219          &context->event, TFTP_SERVER_TICK_INTERVAL);
00220 
00221       //Verify status code
00222       if(!error)
00223       {
00224          //Event-driven processing
00225          for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
00226          {
00227             //Point to the structure describing the current connection
00228             connection = &context->connection[i];
00229 
00230             //Loop through active connections only
00231             if(connection->state != TFTP_STATE_CLOSED)
00232             {
00233                //Check whether a packet has been received
00234                if(context->eventDesc[i].eventFlags & SOCKET_EVENT_RX_READY)
00235                {
00236                   //Process incoming packet
00237                   tftpServerProcessPacket(context, connection);
00238                }
00239             }
00240          }
00241 
00242          //Any connection request received on port 69?
00243          if(context->eventDesc[i].eventFlags & SOCKET_EVENT_RX_READY)
00244          {
00245             //Accept connection request
00246             tftpServerAcceptRequest(context);
00247          }
00248       }
00249 
00250       //Handle periodic operations
00251       tftpServerTick(context);
00252 
00253 #if (NET_RTOS_SUPPORT == ENABLED)
00254    }
00255 #endif
00256 }
00257 
00258 
00259 /**
00260  * @brief Handle periodic operations
00261  * @param[in] context Pointer to the TFTP server context
00262  **/
00263 
00264 void tftpServerTick(TftpServerContext *context)
00265 {
00266    uint_t i;
00267    systime_t time;
00268    TftpClientConnection *connection;
00269 
00270    //Get current time
00271    time = osGetSystemTime();
00272 
00273    //Handle periodic operations
00274    for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
00275    {
00276       //Point to the structure describing the current connection
00277       connection = &context->connection[i];
00278 
00279       //Check current state
00280       if(connection->state == TFTP_STATE_READING ||
00281          connection->state == TFTP_STATE_WRITING ||
00282          connection->state == TFTP_STATE_READ_COMPLETE)
00283       {
00284          //Check current time
00285          if(timeCompare(time, connection->timestamp + TFTP_SERVER_TIMEOUT) >= 0)
00286          {
00287             //Handle retransmissions
00288             if(connection->retransmitCount < TFTP_SERVER_MAX_RETRIES)
00289             {
00290                //Retransmit last packet
00291                tftpServerRetransmitPacket(connection);
00292 
00293                //Save the time at which the packet was sent
00294                connection->timestamp = osGetSystemTime();
00295                //Increment retransmission counter
00296                connection->retransmitCount++;
00297             }
00298             else
00299             {
00300                //Close connection
00301                tftpServerCloseConnection(connection);
00302             }
00303          }
00304       }
00305       else if(connection->state == TFTP_STATE_WRITE_COMPLETE)
00306       {
00307          //The host sending the final ACK will wait for a while before terminating
00308          //in order to retransmit the final ACK if it has been lost
00309          if(timeCompare(time, connection->timestamp + TFTP_SERVER_FINAL_DELAY) >= 0)
00310          {
00311             //Close connection
00312             tftpServerCloseConnection(connection);
00313          }
00314       }
00315    }
00316 }
00317 
00318 
00319 /**
00320  * @brief Accept connection request
00321  * @param[in] context Pointer to the TFTP server context
00322  **/
00323 
00324 void tftpServerAcceptRequest(TftpServerContext *context)
00325 {
00326    error_t error;
00327    size_t length;
00328    uint16_t opcode;
00329    IpAddr clientIpAddr;
00330    uint16_t clientPort;
00331 
00332    //Read incoming TFTP packet
00333    error = socketReceiveFrom(context->socket, &clientIpAddr, &clientPort,
00334       context->packet, TFTP_SERVER_MAX_PACKET_SIZE, &length, 0);
00335 
00336    //Failed to read packet?
00337    if(error)
00338       return;
00339 
00340    //Debug message
00341    TRACE_INFO("TFTP Server: Accepting connection from %s port %" PRIu16 "...\r\n",
00342       ipAddrToString(&clientIpAddr, NULL), clientPort);
00343 
00344    //Sanity check
00345    if(length < sizeof(uint16_t))
00346       return;
00347 
00348    //Retrieve TFTP packet type
00349    opcode = LOAD16BE(context->packet);
00350 
00351    //Read request received?
00352    if(opcode == TFTP_OPCODE_RRQ)
00353    {
00354       //Process RRQ packet
00355       tftpServerProcessRrqPacket(context, &clientIpAddr,
00356          clientPort, (TftpRrqPacket *) context->packet, length);
00357    }
00358    //Write request received?
00359    else if(opcode == TFTP_OPCODE_WRQ)
00360    {
00361       //Process WRQ packet
00362       tftpServerProcessWrqPacket(context, &clientIpAddr,
00363          clientPort, (TftpWrqPacket *) context->packet, length);
00364    }
00365    //Invalid request received?
00366    else
00367    {
00368       //Discard incoming packet
00369    }
00370 }
00371 
00372 
00373 /**
00374  * @brief Process incoming packet
00375  * @param[in] context Pointer to the TFTP server context
00376  * @param[in] connection Pointer to the client connection
00377  **/
00378 
00379 void tftpServerProcessPacket(TftpServerContext *context,
00380    TftpClientConnection *connection)
00381 {
00382    error_t error;
00383    size_t length;
00384    uint16_t opcode;
00385    IpAddr clientIpAddr;
00386    uint16_t clientPort;
00387 
00388    //Read incoming TFTP packet
00389    error = socketReceiveFrom(connection->socket, &clientIpAddr, &clientPort,
00390       context->packet, TFTP_SERVER_MAX_PACKET_SIZE, &length, 0);
00391 
00392    //Failed to read packet?
00393    if(error)
00394       return;
00395 
00396    //Sanity check
00397    if(length < sizeof(uint16_t))
00398       return;
00399 
00400    //Retrieve TFTP packet type
00401    opcode = LOAD16BE(context->packet);
00402 
00403    //Data packet received?
00404    if(opcode == TFTP_OPCODE_DATA)
00405    {
00406       //Process DATA packet
00407       tftpServerProcessDataPacket(connection,
00408          (TftpDataPacket *) context->packet, length);
00409    }
00410    //Acknowledgment packet received?
00411    else if(opcode == TFTP_OPCODE_ACK)
00412    {
00413       //Process ACK packet
00414       tftpServerProcessAckPacket(connection,
00415          (TftpAckPacket *) context->packet, length);
00416    }
00417    //Error packet received?
00418    else if(opcode == TFTP_OPCODE_ERROR)
00419    {
00420       //Process ERROR packet
00421       tftpServerProcessErrorPacket(connection,
00422          (TftpErrorPacket *) context->packet, length);
00423    }
00424    //Invalid packet received?
00425    else
00426    {
00427       //Discard incoming packet
00428    }
00429 }
00430 
00431 
00432 /**
00433  * @brief Process incoming RRQ packet
00434  * @param[in] context Pointer to the TFTP server context
00435  * @param[in] clientIpAddr IP address of the client
00436  * @param[in] clientPort Port number used by the client
00437  * @param[in] rrqPacket Pointer to the RRQ packet
00438  * @param[in] length Length of the packet, in bytes
00439  **/
00440 
00441 void tftpServerProcessRrqPacket(TftpServerContext *context, const IpAddr *clientIpAddr,
00442    uint16_t clientPort, const TftpRrqPacket *rrqPacket, size_t length)
00443 {
00444    const char_t *mode;
00445    TftpClientConnection *connection;
00446 
00447    //Debug message
00448    TRACE_DEBUG("TFTP Server: RRQ packet received (%" PRIuSIZE " bytes)...\r\n",
00449       length);
00450 
00451    //Make sure the length of the RRQ packet is acceptable
00452    if(length <= sizeof(TftpRrqPacket))
00453       return;
00454 
00455    //Compute the number of bytes that follows the 2-byte opcode
00456    length -= sizeof(TftpRrqPacket);
00457 
00458    //Point to the incoming RRQ packet
00459    rrqPacket = (TftpRrqPacket *) context->packet;
00460 
00461    //Malformed RRQ packet?
00462    if(rrqPacket->filename[length - 1] != '\0')
00463       return;
00464 
00465    //Compute the length of the mode string
00466    length -= strlen(rrqPacket->filename) + 1;
00467 
00468    //Malformed RRQ packet?
00469    if(length == 0)
00470       return;
00471 
00472    //Point to the mode string
00473    mode = rrqPacket->filename + strlen(rrqPacket->filename) + 1;
00474 
00475    //Debug message
00476    TRACE_DEBUG("  Opcode = %u\r\n", ntohs(rrqPacket->opcode));
00477    TRACE_DEBUG("  Filename = %s\r\n", rrqPacket->filename);
00478    TRACE_DEBUG("  Mode = %s\r\n", mode);
00479 
00480    //Create a new connection
00481    connection = tftpServerOpenConnection(context, clientIpAddr, clientPort);
00482 
00483    //Any error to report?
00484    if(connection == NULL)
00485       return;
00486 
00487    //Open the specified file for reading
00488    if(context->settings.openFileCallback != NULL)
00489    {
00490       //Invoke user callback function
00491       connection->file = context->settings.openFileCallback(rrqPacket->filename,
00492          mode, FALSE);
00493    }
00494    else
00495    {
00496       //No callback function defined
00497       connection->file = NULL;
00498    }
00499 
00500    //Check if the file was successfully opened
00501    if(connection->file != NULL)
00502    {
00503       //The read operation is in progress...
00504       connection->state = TFTP_STATE_READING;
00505       //Initialize block number
00506       connection->block = 1;
00507 
00508       //Send the first DATA packet
00509       tftpServerSendDataPacket(connection);
00510    }
00511    else
00512    {
00513       //If the reply is an error packet, then the request has been denied
00514       tftpServerSendErrorPacket(connection, TFTP_ERROR_NOT_DEFINED,
00515          "Failed to open file");
00516 
00517       //Close the connection
00518       tftpServerCloseConnection(connection);
00519    }
00520 }
00521 
00522 
00523 /**
00524  * @brief Process incoming WRQ packet
00525  * @param[in] context Pointer to the TFTP server context
00526  * @param[in] clientIpAddr IP address of the client
00527  * @param[in] clientPort Port number used by the client
00528  * @param[in] wrqPacket Pointer to the WRQ packet
00529  * @param[in] length Length of the packet, in bytes
00530  **/
00531 
00532 void tftpServerProcessWrqPacket(TftpServerContext *context, const IpAddr *clientIpAddr,
00533    uint16_t clientPort, const TftpWrqPacket *wrqPacket, size_t length)
00534 {
00535    const char_t *mode;
00536    TftpClientConnection *connection;
00537 
00538    //Debug message
00539    TRACE_DEBUG("TFTP Server: WRQ packet received (%" PRIuSIZE " bytes)...\r\n",
00540       length);
00541 
00542    //Make sure the length of the WRQ packet is acceptable
00543    if(length <= sizeof(TftpWrqPacket))
00544       return;
00545 
00546    //Compute the number of bytes that follows the 2-byte opcode
00547    length -= sizeof(TftpWrqPacket);
00548 
00549    //Point to the incoming WRQ packet
00550    wrqPacket = (TftpWrqPacket *) context->packet;
00551 
00552    //Malformed WRQ packet?
00553    if(wrqPacket->filename[length - 1] != '\0')
00554       return;
00555 
00556    //Compute the length of the mode string
00557    length -= strlen(wrqPacket->filename) + 1;
00558 
00559    //Malformed WRQ packet?
00560    if(length == 0)
00561       return;
00562 
00563    //Point to the mode string
00564    mode = wrqPacket->filename + strlen(wrqPacket->filename) + 1;
00565 
00566    //Debug message
00567    TRACE_DEBUG("  Opcode = %u\r\n", ntohs(wrqPacket->opcode));
00568    TRACE_DEBUG("  Filename = %s\r\n", wrqPacket->filename);
00569    TRACE_DEBUG("  Mode = %s\r\n", mode);
00570 
00571    //Create a new connection
00572    connection = tftpServerOpenConnection(context, clientIpAddr, clientPort);
00573 
00574    //Any error to report?
00575    if(connection == NULL)
00576       return;
00577 
00578    //Open the specified file for writing
00579    if(context->settings.openFileCallback != NULL)
00580    {
00581       //Invoke user callback function
00582       connection->file = context->settings.openFileCallback(wrqPacket->filename,
00583          mode, TRUE);
00584    }
00585    else
00586    {
00587       //No callback function defined
00588       connection->file = NULL;
00589    }
00590 
00591    //Check if the file was successfully opened
00592    if(connection->file != NULL)
00593    {
00594       //The write operation is in progress...
00595       connection->state = TFTP_STATE_WRITING;
00596       //Initialize block number
00597       connection->block = 0;
00598 
00599       //The positive response to a write request is an acknowledgment
00600       //packet with block number zero
00601       tftpServerSendAckPacket(connection);
00602 
00603       //Increment block number
00604       connection->block++;
00605    }
00606    else
00607    {
00608       //If the reply is an error packet, then the request has been denied
00609       tftpServerSendErrorPacket(connection, TFTP_ERROR_NOT_DEFINED,
00610          "Failed to open file");
00611 
00612       //Close the connection
00613       tftpServerCloseConnection(connection);
00614    }
00615 }
00616 
00617 
00618 /**
00619  * @brief Process incoming DATA packet
00620  * @param[in] connection Pointer to the client connection
00621  * @param[in] dataPacket Pointer to the DATA packet
00622  * @param[in] length Length of the packet, in bytes
00623  **/
00624 
00625 void tftpServerProcessDataPacket(TftpClientConnection *connection,
00626    const TftpDataPacket *dataPacket, size_t length)
00627 {
00628    error_t error;
00629    size_t offset;
00630 
00631    //Debug message
00632    TRACE_DEBUG("TFTP Server: DATA packet received (%" PRIuSIZE " bytes)...\r\n",
00633       length);
00634 
00635    //Make sure the length of the DATA packet is acceptable
00636    if(length < sizeof(TftpDataPacket))
00637       return;
00638 
00639    //Calculate the length of the data
00640    length -= sizeof(TftpDataPacket);
00641 
00642    //Debug message
00643    TRACE_DEBUG("  Opcode = %" PRIu16 "\r\n", ntohs(dataPacket->opcode));
00644    TRACE_DEBUG("  Block = %" PRIu16 "\r\n", ntohs(dataPacket->block));
00645 
00646    //Check current state
00647    if(connection->state == TFTP_STATE_WRITING)
00648    {
00649       //Check block number
00650       if(ntohs(dataPacket->block) == connection->block)
00651       {
00652          //Write data to the output file
00653          if(connection->settings->writeFileCallback != NULL)
00654          {
00655             //Calculate the offset relative to the beginning of the file
00656             offset = (connection->block - 1) * TFTP_SERVER_BLOCK_SIZE;
00657 
00658             //Invoke user callback function
00659             error = connection->settings->writeFileCallback(connection->file,
00660                offset, dataPacket->data, length);
00661          }
00662          else
00663          {
00664             //No callback function defined
00665             error = ERROR_WRITE_FAILED;
00666          }
00667 
00668          //Check status code
00669          if(!error)
00670          {
00671             //Acknowledge the DATA packet
00672             tftpServerSendAckPacket(connection);
00673 
00674             //Increment block number
00675             connection->block++;
00676 
00677             //A data packet of less than 512 bytes signals termination of the transfer
00678             if(length < TFTP_SERVER_BLOCK_SIZE)
00679             {
00680                //Properly close the file
00681                if(connection->settings->closeFileCallback != NULL)
00682                {
00683                   //Invoke user callback function
00684                   connection->settings->closeFileCallback(connection->file);
00685                }
00686 
00687                //Mark the file as closed
00688                connection->file = NULL;
00689 
00690                //The host sending the final ACK will wait for a while before terminating
00691                //in order to retransmit the final ACK if it has been lost
00692                connection->state = TFTP_STATE_WRITE_COMPLETE;
00693 
00694                //Save current time
00695                connection->timestamp = osGetSystemTime();
00696             }
00697          }
00698          else
00699          {
00700             //An error occurs during the transfer
00701             tftpServerSendErrorPacket(connection, TFTP_ERROR_NOT_DEFINED,
00702                "Failed to write file");
00703 
00704             //A TFTP server may terminate after sending an error message
00705             tftpServerCloseConnection(connection);
00706          }
00707       }
00708       else
00709       {
00710          //Retransmit ACK packet
00711          tftpServerRetransmitPacket(connection);
00712       }
00713    }
00714    else if(connection->state == TFTP_STATE_WRITE_COMPLETE)
00715    {
00716       //The acknowledger will know that the ACK has been lost if it
00717       //receives the final DATA packet again
00718       tftpServerRetransmitPacket(connection);
00719    }
00720 }
00721 
00722 
00723 /**
00724  * @brief Process incoming ACK packet
00725  * @param[in] connection Pointer to the client connection
00726  * @param[in] ackPacket Pointer to the ACK packet
00727  * @param[in] length Length of the packet, in bytes
00728  **/
00729 
00730 void tftpServerProcessAckPacket(TftpClientConnection *connection,
00731    const TftpAckPacket *ackPacket, size_t length)
00732 {
00733    //Debug message
00734    TRACE_DEBUG("TFTP Server: ACK packet received (%" PRIuSIZE " bytes)...\r\n",
00735       length);
00736 
00737    //Make sure the length of the ACK packet is acceptable
00738    if(length < sizeof(TftpAckPacket))
00739       return;
00740 
00741    //Debug message
00742    TRACE_DEBUG("  Opcode = %" PRIu16 "\r\n", ntohs(ackPacket->opcode));
00743    TRACE_DEBUG("  Block = %" PRIu16 "\r\n", ntohs(ackPacket->block));
00744 
00745    //Check current state
00746    if(connection->state == TFTP_STATE_READING)
00747    {
00748       //Make sure the ACK is not a duplicate
00749       if(ntohs(ackPacket->block) == connection->block)
00750       {
00751          //The block number increases by one for each new block of data
00752          connection->block++;
00753 
00754          //Send DATA packet
00755          tftpServerSendDataPacket(connection);
00756       }
00757    }
00758    else if(connection->state == TFTP_STATE_READ_COMPLETE)
00759    {
00760       //Make sure the ACK is not a duplicate
00761       if(ntohs(ackPacket->block) == connection->block)
00762       {
00763          //The host sending the last DATA must retransmit it until the packet is
00764          //acknowledged or the sending host times out. If the response is an ACK,
00765          //the transmission was completed successfully
00766          tftpServerCloseConnection(connection);
00767       }
00768    }
00769 }
00770 
00771 
00772 /**
00773  * @brief Process incoming ERROR packet
00774  * @param[in] connection Pointer to the client connection
00775  * @param[in] errorPacket Pointer to the ERROR packet
00776  * @param[in] length Length of the packet, in bytes
00777  **/
00778 
00779 void tftpServerProcessErrorPacket(TftpClientConnection *connection,
00780    const TftpErrorPacket *errorPacket, size_t length)
00781 {
00782    //Debug message
00783    TRACE_DEBUG("TFTP Server: ERROR packet received (%" PRIuSIZE " bytes)...\r\n",
00784       length);
00785 
00786    //Make sure the length of the ERROR packet is acceptable
00787    if(length < sizeof(TftpErrorPacket))
00788       return;
00789 
00790    //Debug message
00791    TRACE_DEBUG("  Opcode = %" PRIu16 "\r\n", ntohs(errorPacket->opcode));
00792    TRACE_DEBUG("  Error Code = %" PRIu16 "\r\n", ntohs(errorPacket->errorCode));
00793 
00794    //Compute the length of the error message
00795    length -= sizeof(TftpErrorPacket);
00796 
00797    //Make sure the error message is terminated with a zero byte
00798    if(length > 1 && errorPacket->errorMsg[length - 1] == '\0')
00799    {
00800       //Debug message
00801       TRACE_DEBUG("  Error Msg = %s\r\n", errorPacket->errorMsg);
00802    }
00803 
00804    //Close connection
00805    tftpServerCloseConnection(connection);
00806 }
00807 
00808 
00809 /**
00810  * @brief Send DATA packet
00811  * @param[in] connection Pointer to the client connection
00812  * @return Error code
00813  **/
00814 
00815 error_t tftpServerSendDataPacket(TftpClientConnection *connection)
00816 {
00817    error_t error;
00818    size_t offset;
00819    TftpDataPacket *dataPacket;
00820 
00821    //Point the buffer where to format the packet
00822    dataPacket = (TftpDataPacket *) connection->packet;
00823 
00824    //Format DATA packet
00825    dataPacket->opcode = HTONS(TFTP_OPCODE_DATA);
00826    dataPacket->block = htons(connection->block);
00827 
00828    //Read more data from the input file
00829    if(connection->settings->readFileCallback != NULL)
00830    {
00831       //Calculate the offset relative to the beginning of the file
00832       offset = (connection->block - 1) * TFTP_SERVER_BLOCK_SIZE;
00833 
00834       //Invoke user callback function
00835       error = connection->settings->readFileCallback(connection->file, offset,
00836          dataPacket->data, TFTP_SERVER_BLOCK_SIZE, &connection->packetLen);
00837    }
00838    else
00839    {
00840       //No callback function defined
00841       error = ERROR_READ_FAILED;
00842    }
00843 
00844    //End of file?
00845    if(error == ERROR_END_OF_FILE || error == ERROR_END_OF_STREAM)
00846    {
00847       //Catch exception
00848       error = NO_ERROR;
00849       //This is the the last block of data
00850       connection->packetLen = 0;
00851    }
00852 
00853    //Check status code
00854    if(!error)
00855    {
00856       //A data packet of less than 512 bytes signals termination of the transfer
00857       if(connection->packetLen < TFTP_SERVER_BLOCK_SIZE)
00858       {
00859          //Properly close the file
00860          if(connection->settings->closeFileCallback != NULL)
00861          {
00862             //Invoke user callback function
00863             connection->settings->closeFileCallback(connection->file);
00864          }
00865 
00866          //Mark the file as closed
00867          connection->file = NULL;
00868 
00869          //The host sending the last DATA must retransmit it until the packet
00870          //is acknowledged or the sending host times out
00871          connection->state = TFTP_STATE_READ_COMPLETE;
00872       }
00873 
00874       //Length of the DATA packet
00875       connection->packetLen += sizeof(TftpAckPacket);
00876 
00877       //Debug message
00878       TRACE_DEBUG("TFTP Server: Sending DATA packet (%" PRIuSIZE " bytes)...\r\n", connection->packetLen);
00879       TRACE_DEBUG("  Opcode = %" PRIu16 "\r\n", ntohs(dataPacket->opcode));
00880       TRACE_DEBUG("  Block = %" PRIu16 "\r\n", ntohs(dataPacket->block));
00881 
00882       //Send DATA packet
00883       error = socketSend(connection->socket, connection->packet,
00884          connection->packetLen, NULL, 0);
00885 
00886       //Save the time at which the packet was sent
00887       connection->timestamp = osGetSystemTime();
00888       //Reset retransmission counter
00889       connection->retransmitCount = 0;
00890    }
00891    else
00892    {
00893       //An error occurs during the transfer
00894       tftpServerSendErrorPacket(connection, TFTP_ERROR_NOT_DEFINED,
00895          "Failed to read file");
00896 
00897       //A TFTP server may terminate after sending an error message
00898       tftpServerCloseConnection(connection);
00899    }
00900 
00901    //Return status code
00902    return error;
00903 }
00904 
00905 
00906 /**
00907  * @brief Send ACK packet
00908  * @param[in] connection Pointer to the client connection
00909  * @return Error code
00910  **/
00911 
00912 error_t tftpServerSendAckPacket(TftpClientConnection *connection)
00913 {
00914    error_t error;
00915    TftpAckPacket *ackPacket;
00916 
00917    //Point the buffer where to format the packet
00918    ackPacket = (TftpAckPacket *) connection->packet;
00919 
00920    //Format ACK packet
00921    ackPacket->opcode = HTONS(TFTP_OPCODE_ACK);
00922    ackPacket->block = htons(connection->block);
00923 
00924    //Length of the ACK packet
00925    connection->packetLen = sizeof(TftpAckPacket);
00926 
00927    //Debug message
00928    TRACE_DEBUG("TFTP Server: Sending ACK packet (%" PRIuSIZE " bytes)...\r\n", connection->packetLen);
00929    TRACE_DEBUG("  Opcode = %" PRIu16 "\r\n", ntohs(ackPacket->opcode));
00930    TRACE_DEBUG("  Block = %" PRIu16 "\r\n", ntohs(ackPacket->block));
00931 
00932    //Send ACK packet
00933    error = socketSend(connection->socket, connection->packet,
00934       connection->packetLen, NULL, 0);
00935 
00936    //Save the time at which the packet was sent
00937    connection->timestamp = osGetSystemTime();
00938    //Reset retransmission counter
00939    connection->retransmitCount = 0;
00940 
00941    //Return status code
00942    return error;
00943 }
00944 
00945 
00946 /**
00947  * @brief Send ERROR packet
00948  * @param[in] connection Pointer to the client connection
00949  * @param[in] errorCode Integer indicating the nature of the error
00950  * @param[in] errorMsg Error message intended for human consumption
00951  * @return Error code
00952  **/
00953 
00954 error_t tftpServerSendErrorPacket(TftpClientConnection *connection,
00955    uint16_t errorCode, const char_t *errorMsg)
00956 {
00957    error_t error;
00958    TftpErrorPacket *errorPacket;
00959 
00960    //Check the length of the error message
00961    if(strlen(errorMsg) >= TFTP_SERVER_BLOCK_SIZE)
00962       return ERROR_INVALID_PARAMETER;
00963 
00964    //Point the buffer where to format the packet
00965    errorPacket = (TftpErrorPacket *) connection->packet;
00966 
00967    //Format ERROR packet
00968    errorPacket->opcode = HTONS(TFTP_OPCODE_ERROR);
00969    errorPacket->errorCode = htons(errorCode);
00970 
00971    //Copy error message
00972    strcpy(errorPacket->errorMsg, errorMsg);
00973 
00974    //Length of the ERROR packet
00975    connection->packetLen = sizeof(TftpErrorPacket) + strlen(errorMsg) + 1;
00976 
00977    //Debug message
00978    TRACE_DEBUG("TFTP Server: Sending ERROR packet (%" PRIuSIZE " bytes)...\r\n", connection->packetLen);
00979    TRACE_DEBUG("  Opcode = %" PRIu16 "\r\n", ntohs(errorPacket->opcode));
00980    TRACE_DEBUG("  Error Code = %" PRIu16 "\r\n", ntohs(errorPacket->errorCode));
00981    TRACE_DEBUG("  Error Msg = %s\r\n", errorPacket->errorMsg);
00982 
00983    //Send ERROR packet
00984    error = socketSend(connection->socket, connection->packet,
00985       connection->packetLen, NULL, 0);
00986 
00987    //Save the time at which the packet was sent
00988    connection->timestamp = osGetSystemTime();
00989    //Reset retransmission counter
00990    connection->retransmitCount = 0;
00991 
00992    //Return status code
00993    return error;
00994 }
00995 
00996 
00997 /**
00998  * @brief Retransmit the last packet
00999  * @param[in] connection Pointer to the client connection
01000  * @return Error code
01001  **/
01002 
01003 error_t tftpServerRetransmitPacket(TftpClientConnection *connection)
01004 {
01005    error_t error;
01006 
01007    //Debug message
01008    TRACE_DEBUG("TFTP Server: Retransmitting packet (%" PRIuSIZE " bytes)...\r\n",
01009       connection->packetLen);
01010 
01011    //Retransmit the last packet
01012    error = socketSend(connection->socket, connection->packet,
01013       connection->packetLen, NULL, 0);
01014 
01015    //Return status code
01016    return error;
01017 }
01018 
01019 
01020 /**
01021  * @brief Create client connection
01022  * @param[in] context Pointer to the TFTP server context
01023  * @param[in] clientIpAddr IP address of the client
01024  * @param[in] clientPort Port number used by the client
01025  * @return Pointer to the structure describing the connection
01026  **/
01027 
01028 TftpClientConnection *tftpServerOpenConnection(TftpServerContext *context,
01029    const IpAddr *clientIpAddr, uint16_t clientPort)
01030 {
01031    error_t error;
01032    uint_t i;
01033    TftpClientConnection *connection;
01034    TftpClientConnection *oldestConnection;
01035 
01036    //Keep track of the oldest connection that is waiting to
01037    //retransmit the final ACK
01038    oldestConnection = NULL;
01039 
01040    //Loop through the connection table
01041    for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
01042    {
01043       //Point to the current entry
01044       connection = &context->connection[i];
01045 
01046       //Check the state of the current connection
01047       if(connection->state == TFTP_STATE_CLOSED)
01048       {
01049          //The current entry is available
01050          break;
01051       }
01052       else if(connection->state == TFTP_STATE_WRITE_COMPLETE)
01053       {
01054          //Keep track of the oldest connection that is waiting to
01055          //retransmit the final ACK
01056          if(oldestConnection == NULL)
01057          {
01058             //Save current connection
01059             oldestConnection = connection;
01060          }
01061          else if(timeCompare(connection->timestamp,
01062             oldestConnection->timestamp) < 0)
01063          {
01064             //Save current connection
01065             oldestConnection = connection;
01066          }
01067       }
01068    }
01069 
01070    //The oldest connection that is waiting to retransmit the final ACK
01071    //can be reused when the connection table runs out of space
01072    if(i >= TFTP_SERVER_MAX_CONNECTIONS)
01073    {
01074       //Close the oldest connection
01075       tftpServerCloseConnection(oldestConnection);
01076       //Reuse the connection
01077       connection = oldestConnection;
01078    }
01079 
01080    //Failed to create a new connection?
01081    if(connection == NULL)
01082       return NULL;
01083 
01084    //Clear the structure describing the connection
01085    memset(connection, 0, sizeof(TftpClientConnection));
01086 
01087    //Open a UDP socket
01088    connection->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
01089 
01090    //Failed to open socket?
01091    if(connection->socket == NULL)
01092       return NULL;
01093 
01094    //Associate the socket with the relevant interface
01095    error = socketBindToInterface(connection->socket, context->settings.interface);
01096 
01097    //Any error to report?
01098    if(error)
01099    {
01100       //Clean up side effects
01101       socketClose(connection->socket);
01102       connection->socket = NULL;
01103       //Exit immediately
01104       return NULL;
01105    }
01106 
01107    //Connect the socket to the remote TFTP client
01108    error = socketConnect(connection->socket, clientIpAddr, clientPort);
01109 
01110    //Any error to report?
01111    if(error)
01112    {
01113       //Clean up side effects
01114       socketClose(connection->socket);
01115       connection->socket = NULL;
01116       //Exit immediately
01117       return NULL;
01118    }
01119 
01120    //Reference to the TFTP server settings
01121    connection->settings = &context->settings;
01122    //Update connection state
01123    connection->state = TFTP_STATE_OPEN;
01124 
01125    //Pointer to the structure describing the connection
01126    return connection;
01127 }
01128 
01129 
01130 /**
01131  * @brief Close client connection
01132  * @param[in] connection Pointer to the client connection
01133  **/
01134 
01135 void tftpServerCloseConnection(TftpClientConnection *connection)
01136 {
01137    //Debug message
01138    TRACE_INFO("TFTP Server: Closing connection...\r\n");
01139 
01140    //Any active connection?
01141    if(connection->socket != NULL)
01142    {
01143       //Close UDP socket
01144       socketClose(connection->socket);
01145       connection->socket = NULL;
01146    }
01147 
01148    //Check whether a read or write operation is in progress...
01149    if(connection->file != NULL)
01150    {
01151       //Properly close the file before closing the connection
01152       if(connection->settings->closeFileCallback != NULL)
01153       {
01154          //Invoke user callback function
01155          connection->settings->closeFileCallback(connection->file);
01156       }
01157 
01158       //Mark the file as closed
01159       connection->file = NULL;
01160    }
01161 
01162    //Mark the connection as closed
01163    connection->state = TFTP_STATE_CLOSED;
01164 }
01165 
01166 #endif
01167