Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:17 by
