tftp_server_misc.c
Go to the documentation of this file.
1 /**
2  * @file tftp_server_misc.c
3  * @brief Helper functions for TFTP server
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TFTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "tftp/tftp_server.h"
37 #include "tftp/tftp_server_misc.h"
38 #include "debug.h"
39 
40 //Check TCP/IP stack configuration
41 #if (TFTP_SERVER_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Handle periodic operations
46  * @param[in] context Pointer to the TFTP server context
47  **/
48 
50 {
51  uint_t i;
53  TftpClientConnection *connection;
54 
55  //Get current time
57 
58  //Handle periodic operations
59  for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
60  {
61  //Point to the structure describing the current connection
62  connection = &context->connection[i];
63 
64  //Check current state
65  if(connection->state == TFTP_STATE_READING ||
66  connection->state == TFTP_STATE_WRITING ||
67  connection->state == TFTP_STATE_READ_COMPLETE)
68  {
69  //Check current time
70  if((time - connection->timestamp) >= TFTP_SERVER_TIMEOUT)
71  {
72  //Handle retransmissions
73  if(connection->retransmitCount < TFTP_SERVER_MAX_RETRIES)
74  {
75  //Retransmit the last packet
76  tftpServerRetransmitPacket(connection);
77 
78  //Save the time at which the packet was sent
79  connection->timestamp = osGetSystemTime();
80  //Increment retransmission counter
81  connection->retransmitCount++;
82  }
83  else
84  {
85  //Close connection
86  tftpServerCloseConnection(connection);
87  }
88  }
89  }
90  else if(connection->state == TFTP_STATE_WRITE_COMPLETE)
91  {
92  //The host sending the final ACK will wait for a while before
93  //terminating in order to retransmit the final ACK if it has been
94  //lost (refer to RFC 1350, section 6)
95  if((time - connection->timestamp) >= TFTP_SERVER_FINAL_DELAY)
96  {
97  //Close connection
98  tftpServerCloseConnection(connection);
99  }
100  }
101  }
102 }
103 
104 
105 /**
106  * @brief Find a connection that matches a given client
107  * @param[in] context Pointer to the TFTP server context
108  * @param[in] interface Network interface
109  * @param[in] clientIpAddr IP address of the client
110  * @param[in] clientPort Port number used by the client
111  * @return Pointer to the matching connection, if any
112  **/
113 
115  NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort)
116 {
117  uint_t i;
118  TftpClientConnection *connection;
119 
120  //Loop through the connection table
121  for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
122  {
123  //Point to the current entry
124  connection = &context->connection[i];
125 
126  //Check the state of the current connection
127  if(connection->state != TFTP_STATE_CLOSED)
128  {
129  //Matching connection found?
130  if(connection->interface == interface &&
131  ipCompAddr(&connection->clientIpAddr, clientIpAddr) &&
132  connection->clientPort == clientPort)
133  {
134  return connection;
135  }
136  }
137  }
138 
139  //No matching connection found
140  return NULL;
141 }
142 
143 
144 /**
145  * @brief Create a new connection
146  * @param[in] context Pointer to the TFTP server context
147  * @param[in] interface Network interface to be used
148  * @param[in] clientIpAddr IP address of the client
149  * @param[in] clientPort Port number used by the client
150  * @return Pointer to the structure describing the connection
151  **/
152 
154  NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort)
155 {
156  error_t error;
157  uint_t i;
158  systime_t time;
159  Socket *socket;
160  TftpClientConnection *connection;
161  TftpClientConnection *oldestConnection;
162 
163  //Get current time
164  time = osGetSystemTime();
165 
166  //Keep track of the oldest connection that is waiting to retransmit
167  //the final ACK
168  oldestConnection = NULL;
169 
170  //Loop through the connection table
171  for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
172  {
173  //Point to the current entry
174  connection = &context->connection[i];
175 
176  //Check the state of the current connection
177  if(connection->state == TFTP_STATE_CLOSED)
178  {
179  //The current entry is available
180  break;
181  }
182  else if(connection->state == TFTP_STATE_WRITE_COMPLETE)
183  {
184  //Keep track of the oldest connection that is waiting to retransmit
185  //the final ACK
186  if(oldestConnection == NULL)
187  {
188  oldestConnection = connection;
189  }
190  else if((time - connection->timestamp) > (time - oldestConnection->timestamp))
191  {
192  oldestConnection = connection;
193  }
194  }
195  }
196 
197  //The oldest connection that is waiting to retransmit the final ACK can be
198  //reused when the connection table runs out of space
200  {
201  //Close the oldest connection
202  tftpServerCloseConnection(oldestConnection);
203  //Reuse the connection
204  connection = oldestConnection;
205  }
206 
207  //Valid connection?
208  if(connection != NULL)
209  {
210  //Open a UDP socket
211  socket = socketOpenEx(context->netContext, SOCKET_TYPE_DGRAM,
213 
214  //Valid socket handle?
215  if(socket != NULL)
216  {
217  //Associate the socket with the relevant interface
218  error = socketBindToInterface(socket, interface);
219 
220  //Check status code
221  if(!error)
222  {
223  //Connect the socket to the remote TFTP client
224  error = socketConnect(socket, clientIpAddr, clientPort);
225  }
226 
227  //Check status code
228  if(!error)
229  {
230  //Clear the structure describing the connection
231  osMemset(connection, 0, sizeof(TftpClientConnection));
232 
233  //Attach TFTP server context
234  connection->context = context;
235  //Attach socket handle
236  connection->socket = socket;
237 
238  //Save client's parameters
239  connection->interface = interface;
240  connection->clientIpAddr = *clientIpAddr;
241  connection->clientPort = clientPort;
242 
243  //Update connection state
244  connection->state = TFTP_STATE_OPEN;
245  }
246  else
247  {
248  //Clean up side effects
250  }
251  }
252  else
253  {
254  //Failed to open socket
255  error = ERROR_OPEN_FAILED;
256  }
257  }
258 
259  //Pointer to the structure describing the connection
260  return (error == NO_ERROR) ? connection : NULL;
261 }
262 
263 
264 /**
265  * @brief Close connection
266  * @param[in] connection Pointer to the client connection
267  **/
268 
270 {
271  //Valid connection?
272  if(connection != NULL)
273  {
274  //Debug message
275  TRACE_INFO("TFTP Server: Closing connection...\r\n");
276 
277  //Any active connection?
278  if(connection->socket != NULL)
279  {
280  //Close UDP socket
281  socketClose(connection->socket);
282  connection->socket = NULL;
283  }
284 
285  //Check whether a read or write operation is in progress
286  if(connection->file != NULL)
287  {
288  //Properly close the file before closing the connection
289  if(connection->context->closeFileCallback != NULL)
290  {
291  //Invoke user callback function
292  connection->context->closeFileCallback(connection->file);
293  }
294 
295  //Mark the file as closed
296  connection->file = NULL;
297  }
298 
299  //Mark the connection as closed
300  connection->state = TFTP_STATE_CLOSED;
301  }
302 }
303 
304 
305 /**
306  * @brief Accept connection request
307  * @param[in] context Pointer to the TFTP server context
308  **/
309 
311 {
312  error_t error;
313  uint16_t opcode;
314  SocketMsg msg;
315 
316  //Point to the receive buffer
317  msg = SOCKET_DEFAULT_MSG;
318  msg.data = context->packet;
320 
321  //Read incoming TFTP packet
322  error = socketReceiveMsg(context->socket, &msg, 0);
323 
324  //Check status code
325  if(!error)
326  {
327  //Make sure the length of the packet is acceptable
328  if(msg.length >= sizeof(uint16_t))
329  {
330  //Debug message
331  TRACE_INFO("TFTP Server: Accepting connection from %s port %" PRIu16 "...\r\n",
332  ipAddrToString(&msg.srcIpAddr, NULL), msg.srcPort);
333 
334  //The TFTP header consists of a 2 byte opcode field which indicates
335  //the packet's type (refer to RFC 1350, section 3)
336  opcode = LOAD16BE(context->packet);
337 
338  //Check packet type
339  if(opcode == TFTP_OPCODE_RRQ)
340  {
341  //Process RRQ packet
343  msg.srcPort, (TftpRrqPacket *) context->packet, msg.length);
344  }
345  else if(opcode == TFTP_OPCODE_WRQ)
346  {
347  //Process WRQ packet
349  msg.srcPort, (TftpWrqPacket *) context->packet, msg.length);
350  }
351  else
352  {
353  //Discard incoming packet
354  }
355  }
356  }
357 }
358 
359 
360 /**
361  * @brief Process incoming packet
362  * @param[in] context Pointer to the TFTP server context
363  * @param[in] connection Pointer to the client connection
364  **/
365 
367  TftpClientConnection *connection)
368 {
369  error_t error;
370  size_t length;
371  uint16_t opcode;
372  IpAddr clientIpAddr;
373  uint16_t clientPort;
374 
375  //Read incoming TFTP packet
376  error = socketReceiveFrom(connection->socket, &clientIpAddr, &clientPort,
377  context->packet, TFTP_SERVER_MAX_PACKET_SIZE, &length, 0);
378 
379  //Check status code
380  if(!error)
381  {
382  //Make sure the length of the packet is acceptable
383  if(length >= sizeof(uint16_t))
384  {
385  //The TFTP header consists of a 2 byte opcode field which indicates
386  //the packet's type (refer to RFC 1350, section 3)
387  opcode = LOAD16BE(context->packet);
388 
389  //Check packet type
390  if(opcode == TFTP_OPCODE_DATA)
391  {
392  //Process DATA packet
393  tftpServerProcessDataPacket(connection,
394  (TftpDataPacket *) context->packet, length);
395  }
396  else if(opcode == TFTP_OPCODE_ACK)
397  {
398  //Process ACK packet
399  tftpServerProcessAckPacket(connection,
400  (TftpAckPacket *) context->packet, length);
401  }
402  else if(opcode == TFTP_OPCODE_ERROR)
403  {
404  //Process ERROR packet
405  tftpServerProcessErrorPacket(connection,
406  (TftpErrorPacket *) context->packet, length);
407  }
408  else
409  {
410  //Discard incoming packet
411  }
412  }
413  }
414 }
415 
416 
417 /**
418  * @brief Process incoming RRQ packet
419  * @param[in] context Pointer to the TFTP server context
420  * @param[in] interface Network interface on which the packet was received
421  * @param[in] clientIpAddr IP address of the client
422  * @param[in] clientPort Port number used by the client
423  * @param[in] rrqPacket Pointer to the RRQ packet
424  * @param[in] length Length of the packet, in bytes
425  **/
426 
428  NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort,
429  const TftpRrqPacket *rrqPacket, size_t length)
430 {
431  const char_t *mode;
432  TftpClientConnection *connection;
433 
434  //Debug message
435  TRACE_DEBUG("TFTP Server: RRQ packet received (%" PRIuSIZE " bytes)...\r\n",
436  length);
437 
438  //Make sure the length of the RRQ packet is acceptable
439  if(length <= sizeof(TftpRrqPacket))
440  return;
441 
442  //Compute the number of bytes that follows the 2-byte opcode
443  length -= sizeof(TftpRrqPacket);
444 
445  //Point to the incoming RRQ packet
446  rrqPacket = (TftpRrqPacket *) context->packet;
447 
448  //Malformed RRQ packet?
449  if(rrqPacket->filename[length - 1] != '\0')
450  return;
451 
452  //Compute the length of the mode string
453  length -= osStrlen(rrqPacket->filename) + 1;
454 
455  //Malformed RRQ packet?
456  if(length == 0)
457  return;
458 
459  //Point to the mode string
460  mode = rrqPacket->filename + osStrlen(rrqPacket->filename) + 1;
461 
462  //Debug message
463  TRACE_DEBUG(" Opcode = %u\r\n", ntohs(rrqPacket->opcode));
464  TRACE_DEBUG(" Filename = %s\r\n", rrqPacket->filename);
465  TRACE_DEBUG(" Mode = %s\r\n", mode);
466 
467  //Check whether a matching connection exists
468  connection = tftpServerFindConnection(context, interface, clientIpAddr,
469  clientPort);
470 
471  //Matching connection found?
472  if(connection != NULL)
473  {
474  //Retransmit the first DATA packet
475  tftpServerRetransmitPacket(connection);
476  }
477  else
478  {
479  //Create a new connection
480  connection = tftpServerOpenConnection(context, interface, clientIpAddr,
481  clientPort);
482 
483  //Valid connection?
484  if(connection != NULL)
485  {
486  //Open the specified file for reading
487  if(context->openFileCallback != NULL)
488  {
489  //Invoke user callback function
490  connection->file = context->openFileCallback(rrqPacket->filename,
491  mode, FALSE);
492  }
493  else
494  {
495  //No callback function defined
496  connection->file = NULL;
497  }
498 
499  //Check if the file was successfully opened
500  if(connection->file != NULL)
501  {
502  //The read operation is in progress
503  connection->state = TFTP_STATE_READING;
504  //Initialize block number
505  connection->block = 1;
506 
507  //Send the first DATA packet
508  tftpServerSendDataPacket(connection);
509  }
510  else
511  {
512  //If the reply is an error packet, then the request has been denied
513  //refer to RFC 1350, section 4)
515  "Failed to open file");
516 
517  //Close the connection
518  tftpServerCloseConnection(connection);
519  }
520  }
521  }
522 }
523 
524 
525 /**
526  * @brief Process incoming WRQ packet
527  * @param[in] context Pointer to the TFTP server context
528  * @param[in] interface Network interface on which the packet was received
529  * @param[in] clientIpAddr IP address of the client
530  * @param[in] clientPort Port number used by the client
531  * @param[in] wrqPacket Pointer to the WRQ packet
532  * @param[in] length Length of the packet, in bytes
533  **/
534 
536  NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort,
537  const TftpWrqPacket *wrqPacket, size_t length)
538 {
539  const char_t *mode;
540  TftpClientConnection *connection;
541 
542  //Debug message
543  TRACE_DEBUG("TFTP Server: WRQ packet received (%" PRIuSIZE " bytes)...\r\n",
544  length);
545 
546  //Make sure the length of the WRQ packet is acceptable
547  if(length <= sizeof(TftpWrqPacket))
548  return;
549 
550  //Compute the number of bytes that follows the 2-byte opcode
551  length -= sizeof(TftpWrqPacket);
552 
553  //Point to the incoming WRQ packet
554  wrqPacket = (TftpWrqPacket *) context->packet;
555 
556  //Malformed WRQ packet?
557  if(wrqPacket->filename[length - 1] != '\0')
558  return;
559 
560  //Compute the length of the mode string
561  length -= osStrlen(wrqPacket->filename) + 1;
562 
563  //Malformed WRQ packet?
564  if(length == 0)
565  return;
566 
567  //Point to the mode string
568  mode = wrqPacket->filename + osStrlen(wrqPacket->filename) + 1;
569 
570  //Debug message
571  TRACE_DEBUG(" Opcode = %u\r\n", ntohs(wrqPacket->opcode));
572  TRACE_DEBUG(" Filename = %s\r\n", wrqPacket->filename);
573  TRACE_DEBUG(" Mode = %s\r\n", mode);
574 
575  //Check whether a matching connection exists
576  connection = tftpServerFindConnection(context, interface, clientIpAddr,
577  clientPort);
578 
579  //Matching connection found?
580  if(connection != NULL)
581  {
582  //Retransmit the ACK packet
583  tftpServerRetransmitPacket(connection);
584  }
585  else
586  {
587  //Create a new connection
588  connection = tftpServerOpenConnection(context, interface, clientIpAddr,
589  clientPort);
590 
591  //Valid connection?
592  if(connection != NULL)
593  {
594  //Open the specified file for writing
595  if(context->openFileCallback != NULL)
596  {
597  //Invoke user callback function
598  connection->file = context->openFileCallback(wrqPacket->filename,
599  mode, TRUE);
600  }
601  else
602  {
603  //No callback function defined
604  connection->file = NULL;
605  }
606 
607  //Check if the file was successfully opened
608  if(connection->file != NULL)
609  {
610  //The write operation is in progress
611  connection->state = TFTP_STATE_WRITING;
612  //Initialize block number
613  connection->block = 0;
614 
615  //The positive response to a write request is an acknowledgment
616  //packet with block number zero
617  tftpServerSendAckPacket(connection);
618 
619  //Increment block number
620  connection->block++;
621  }
622  else
623  {
624  //If the reply is an error packet, then the request has been denied
625  //refer to RFC 1350, section 4)
627  "Failed to open file");
628 
629  //Close the connection
630  tftpServerCloseConnection(connection);
631  }
632  }
633  }
634 }
635 
636 
637 /**
638  * @brief Process incoming DATA packet
639  * @param[in] connection Pointer to the client connection
640  * @param[in] dataPacket Pointer to the DATA packet
641  * @param[in] length Length of the packet, in bytes
642  **/
643 
645  const TftpDataPacket *dataPacket, size_t length)
646 {
647  error_t error;
648  size_t offset;
649 
650  //Debug message
651  TRACE_DEBUG("TFTP Server: DATA packet received (%" PRIuSIZE " bytes)...\r\n",
652  length);
653 
654  //Make sure the length of the DATA packet is acceptable
655  if(length < sizeof(TftpDataPacket))
656  return;
657 
658  //Calculate the length of the data
659  length -= sizeof(TftpDataPacket);
660 
661  //Debug message
662  TRACE_DEBUG(" Opcode = %" PRIu16 "\r\n", ntohs(dataPacket->opcode));
663  TRACE_DEBUG(" Block = %" PRIu16 "\r\n", ntohs(dataPacket->block));
664 
665  //Check current state
666  if(connection->state == TFTP_STATE_WRITING)
667  {
668  //Check block number
669  if(ntohs(dataPacket->block) == connection->block)
670  {
671  //Write data to the output file
672  if(connection->context->writeFileCallback != NULL)
673  {
674  //Calculate the offset relative to the beginning of the file
675  offset = (connection->block - 1) * TFTP_SERVER_BLOCK_SIZE;
676 
677  //Invoke user callback function
678  error = connection->context->writeFileCallback(connection->file,
679  offset, dataPacket->data, length);
680  }
681  else
682  {
683  //No callback function defined
684  error = ERROR_WRITE_FAILED;
685  }
686 
687  //Check status code
688  if(!error)
689  {
690  //Acknowledge the DATA packet
691  tftpServerSendAckPacket(connection);
692 
693  //Increment block number
694  connection->block++;
695 
696  //A data packet of less than 512 bytes signals termination of the transfer
698  {
699  //Properly close the file
700  if(connection->context->closeFileCallback != NULL)
701  {
702  //Invoke user callback function
703  connection->context->closeFileCallback(connection->file);
704  }
705 
706  //Mark the file as closed
707  connection->file = NULL;
708 
709  //The host sending the final ACK will wait for a while before terminating
710  //in order to retransmit the final ACK if it has been lost
711  connection->state = TFTP_STATE_WRITE_COMPLETE;
712 
713  //Save current time
714  connection->timestamp = osGetSystemTime();
715  }
716  }
717  else
718  {
719  //An error occurs during the transfer
721  "Failed to write file");
722 
723  //A TFTP server may terminate after sending an error message
724  tftpServerCloseConnection(connection);
725  }
726  }
727  else
728  {
729  //Retransmit the ACK packet
730  tftpServerRetransmitPacket(connection);
731  }
732  }
733  else if(connection->state == TFTP_STATE_WRITE_COMPLETE)
734  {
735  //The acknowledger will know that the ACK has been lost if it receives
736  //the final DATA packet again (refer to RFC 1350, section 6)
737  tftpServerRetransmitPacket(connection);
738  }
739 }
740 
741 
742 /**
743  * @brief Process incoming ACK packet
744  * @param[in] connection Pointer to the client connection
745  * @param[in] ackPacket Pointer to the ACK packet
746  * @param[in] length Length of the packet, in bytes
747  **/
748 
750  const TftpAckPacket *ackPacket, size_t length)
751 {
752  //Debug message
753  TRACE_DEBUG("TFTP Server: ACK packet received (%" PRIuSIZE " bytes)...\r\n",
754  length);
755 
756  //Make sure the length of the ACK packet is acceptable
757  if(length < sizeof(TftpAckPacket))
758  return;
759 
760  //Debug message
761  TRACE_DEBUG(" Opcode = %" PRIu16 "\r\n", ntohs(ackPacket->opcode));
762  TRACE_DEBUG(" Block = %" PRIu16 "\r\n", ntohs(ackPacket->block));
763 
764  //Check current state
765  if(connection->state == TFTP_STATE_READING)
766  {
767  //Make sure the ACK is not a duplicate
768  if(ntohs(ackPacket->block) == connection->block)
769  {
770  //The block number increases by one for each new block of data
771  connection->block++;
772 
773  //Send DATA packet
774  tftpServerSendDataPacket(connection);
775  }
776  else
777  {
778  //Implementations must never resend the current DATA packet on
779  //receipt of a duplicate ACK (refer to RFC 1123, section 4.2.3.1)
780  }
781  }
782  else if(connection->state == TFTP_STATE_READ_COMPLETE)
783  {
784  //Make sure the ACK is not a duplicate
785  if(ntohs(ackPacket->block) == connection->block)
786  {
787  //The host sending the last DATA must retransmit it until the packet
788  //is acknowledged or the sending host times out. If the response is an
789  //ACK, the transmission was completed successfully (refer to RFC 1350,
790  //section 6)
791  tftpServerCloseConnection(connection);
792  }
793  }
794 }
795 
796 
797 /**
798  * @brief Process incoming ERROR packet
799  * @param[in] connection Pointer to the client connection
800  * @param[in] errorPacket Pointer to the ERROR packet
801  * @param[in] length Length of the packet, in bytes
802  **/
803 
805  const TftpErrorPacket *errorPacket, size_t length)
806 {
807  //Debug message
808  TRACE_DEBUG("TFTP Server: ERROR packet received (%" PRIuSIZE " bytes)...\r\n",
809  length);
810 
811  //Make sure the length of the ERROR packet is acceptable
812  if(length < sizeof(TftpErrorPacket))
813  return;
814 
815  //Debug message
816  TRACE_DEBUG(" Opcode = %" PRIu16 "\r\n", ntohs(errorPacket->opcode));
817  TRACE_DEBUG(" Error Code = %" PRIu16 "\r\n", ntohs(errorPacket->errorCode));
818 
819  //Compute the length of the error message
820  length -= sizeof(TftpErrorPacket);
821 
822  //Make sure the error message is terminated with a zero byte
823  if(length > 1 && errorPacket->errorMsg[length - 1] == '\0')
824  {
825  //Debug message
826  TRACE_DEBUG(" Error Msg = %s\r\n", errorPacket->errorMsg);
827  }
828 
829  //Close connection
830  tftpServerCloseConnection(connection);
831 }
832 
833 
834 /**
835  * @brief Send DATA packet
836  * @param[in] connection Pointer to the client connection
837  * @return Error code
838  **/
839 
841 {
842  error_t error;
843  size_t offset;
844  TftpDataPacket *dataPacket;
845 
846  //Point to the buffer where to format the packet
847  dataPacket = (TftpDataPacket *) connection->packet;
848 
849  //Format DATA packet
850  dataPacket->opcode = HTONS(TFTP_OPCODE_DATA);
851  dataPacket->block = htons(connection->block);
852 
853  //Read more data from the input file
854  if(connection->context->readFileCallback != NULL)
855  {
856  //Calculate the offset relative to the beginning of the file
857  offset = (connection->block - 1) * TFTP_SERVER_BLOCK_SIZE;
858 
859  //Invoke user callback function
860  error = connection->context->readFileCallback(connection->file, offset,
861  dataPacket->data, TFTP_SERVER_BLOCK_SIZE, &connection->packetLen);
862  }
863  else
864  {
865  //No callback function defined
866  error = ERROR_READ_FAILED;
867  }
868 
869  //End of file?
870  if(error == ERROR_END_OF_FILE || error == ERROR_END_OF_STREAM)
871  {
872  //Catch exception
873  error = NO_ERROR;
874  //This is the last block of data
875  connection->packetLen = 0;
876  }
877 
878  //Check status code
879  if(!error)
880  {
881  //A data packet of less than 512 bytes signals termination of the transfer
882  if(connection->packetLen < TFTP_SERVER_BLOCK_SIZE)
883  {
884  //Properly close the file
885  if(connection->context->closeFileCallback != NULL)
886  {
887  //Invoke user callback function
888  connection->context->closeFileCallback(connection->file);
889  }
890 
891  //Mark the file as closed
892  connection->file = NULL;
893 
894  //The host sending the last DATA must retransmit it until the packet
895  //is acknowledged or the sending host times out
896  connection->state = TFTP_STATE_READ_COMPLETE;
897  }
898 
899  //Length of the DATA packet
900  connection->packetLen += sizeof(TftpAckPacket);
901 
902  //Debug message
903  TRACE_DEBUG("TFTP Server: Sending DATA packet (%" PRIuSIZE " bytes)...\r\n", connection->packetLen);
904  TRACE_DEBUG(" Opcode = %" PRIu16 "\r\n", ntohs(dataPacket->opcode));
905  TRACE_DEBUG(" Block = %" PRIu16 "\r\n", ntohs(dataPacket->block));
906 
907  //Send DATA packet
908  error = socketSend(connection->socket, connection->packet,
909  connection->packetLen, NULL, 0);
910 
911  //Save the time at which the packet was sent
912  connection->timestamp = osGetSystemTime();
913  //Reset retransmission counter
914  connection->retransmitCount = 0;
915  }
916  else
917  {
918  //An error occurs during the transfer
920  "Failed to read file");
921 
922  //A TFTP server may terminate after sending an error message
923  tftpServerCloseConnection(connection);
924  }
925 
926  //Return status code
927  return error;
928 }
929 
930 
931 /**
932  * @brief Send ACK packet
933  * @param[in] connection Pointer to the client connection
934  * @return Error code
935  **/
936 
938 {
939  error_t error;
940  TftpAckPacket *ackPacket;
941 
942  //Point to the buffer where to format the packet
943  ackPacket = (TftpAckPacket *) connection->packet;
944 
945  //Format ACK packet
946  ackPacket->opcode = HTONS(TFTP_OPCODE_ACK);
947  ackPacket->block = htons(connection->block);
948 
949  //Length of the ACK packet
950  connection->packetLen = sizeof(TftpAckPacket);
951 
952  //Debug message
953  TRACE_DEBUG("TFTP Server: Sending ACK packet (%" PRIuSIZE " bytes)...\r\n", connection->packetLen);
954  TRACE_DEBUG(" Opcode = %" PRIu16 "\r\n", ntohs(ackPacket->opcode));
955  TRACE_DEBUG(" Block = %" PRIu16 "\r\n", ntohs(ackPacket->block));
956 
957  //Send ACK packet
958  error = socketSend(connection->socket, connection->packet,
959  connection->packetLen, NULL, 0);
960 
961  //Save the time at which the packet was sent
962  connection->timestamp = osGetSystemTime();
963  //Reset retransmission counter
964  connection->retransmitCount = 0;
965 
966  //Return status code
967  return error;
968 }
969 
970 
971 /**
972  * @brief Send ERROR packet
973  * @param[in] connection Pointer to the client connection
974  * @param[in] errorCode Integer indicating the nature of the error
975  * @param[in] errorMsg Error message intended for human consumption
976  * @return Error code
977  **/
978 
980  uint16_t errorCode, const char_t *errorMsg)
981 {
982  error_t error;
983  TftpErrorPacket *errorPacket;
984 
985  //Check the length of the error message
988 
989  //Point to the buffer where to format the packet
990  errorPacket = (TftpErrorPacket *) connection->packet;
991 
992  //Format ERROR packet
993  errorPacket->opcode = HTONS(TFTP_OPCODE_ERROR);
994  errorPacket->errorCode = htons(errorCode);
995 
996  //Copy error message
997  osStrcpy(errorPacket->errorMsg, errorMsg);
998 
999  //Length of the ERROR packet
1000  connection->packetLen = sizeof(TftpErrorPacket) + osStrlen(errorMsg) + 1;
1001 
1002  //Debug message
1003  TRACE_DEBUG("TFTP Server: Sending ERROR packet (%" PRIuSIZE " bytes)...\r\n", connection->packetLen);
1004  TRACE_DEBUG(" Opcode = %" PRIu16 "\r\n", ntohs(errorPacket->opcode));
1005  TRACE_DEBUG(" Error Code = %" PRIu16 "\r\n", ntohs(errorPacket->errorCode));
1006  TRACE_DEBUG(" Error Msg = %s\r\n", errorPacket->errorMsg);
1007 
1008  //Send ERROR packet
1009  error = socketSend(connection->socket, connection->packet,
1010  connection->packetLen, NULL, 0);
1011 
1012  //Save the time at which the packet was sent
1013  connection->timestamp = osGetSystemTime();
1014  //Reset retransmission counter
1015  connection->retransmitCount = 0;
1016 
1017  //Return status code
1018  return error;
1019 }
1020 
1021 
1022 /**
1023  * @brief Retransmit the last packet
1024  * @param[in] connection Pointer to the client connection
1025  * @return Error code
1026  **/
1027 
1029 {
1030  error_t error;
1031 
1032  //Debug message
1033  TRACE_DEBUG("TFTP Server: Retransmitting packet (%" PRIuSIZE " bytes)...\r\n",
1034  connection->packetLen);
1035 
1036  //Retransmit the last packet
1037  error = socketSend(connection->socket, connection->packet,
1038  connection->packetLen, NULL, 0);
1039 
1040  //Return status code
1041  return error;
1042 }
1043 
1044 #endif
error_t socketSend(Socket *socket, const void *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: socket.c:1514
char_t errorMsg[]
Definition: tftp_common.h:139
#define htons(value)
Definition: cpu_endian.h:413
void tftpServerProcessWrqPacket(TftpServerContext *context, NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort, const TftpWrqPacket *wrqPacket, size_t length)
Process incoming WRQ packet.
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:108
uint8_t opcode
Definition: dns_common.h:191
void tftpServerProcessPacket(TftpServerContext *context, TftpClientConnection *connection)
Process incoming packet.
@ TFTP_ERROR_NOT_DEFINED
Definition: tftp_common.h:67
@ TFTP_STATE_WRITING
Definition: tftp_server.h:130
IP network address.
Definition: ip.h:90
#define TFTP_SERVER_MAX_RETRIES
Definition: tftp_server.h:73
#define TRUE
Definition: os_port.h:50
void tftpServerCloseConnection(TftpClientConnection *connection)
Close connection.
Message and ancillary data.
Definition: socket.h:241
TftpClientConnection * tftpServerOpenConnection(TftpServerContext *context, NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort)
Create a new connection.
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2094
TftpErrorPacket
Definition: tftp_common.h:140
#define TftpServerContext
Definition: tftp_server.h:113
@ TFTP_OPCODE_ACK
Acknowledgment.
Definition: tftp_common.h:55
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:810
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
void * data
Pointer to the payload.
Definition: socket.h:242
@ TFTP_OPCODE_WRQ
Write request.
Definition: tftp_common.h:53
TftpClientConnection * tftpServerFindConnection(TftpServerContext *context, NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort)
Find a connection that matches a given client.
error_t tftpServerRetransmitPacket(TftpClientConnection *connection)
Retransmit the last packet.
#define osStrlen(s)
Definition: os_port.h:171
uint16_t errorCode
Definition: tftp_common.h:138
void tftpServerProcessRrqPacket(TftpServerContext *context, NetInterface *interface, const IpAddr *clientIpAddr, uint16_t clientPort, const TftpRrqPacket *rrqPacket, size_t length)
Process incoming RRQ packet.
@ ERROR_END_OF_STREAM
Definition: error.h:211
TFTP server.
error_t tftpServerSendErrorPacket(TftpClientConnection *connection, uint16_t errorCode, const char_t *errorMsg)
Send ERROR packet.
@ ERROR_OPEN_FAILED
Definition: error.h:75
void tftpServerProcessErrorPacket(TftpClientConnection *connection, const TftpErrorPacket *errorPacket, size_t length)
Process incoming ERROR packet.
@ TFTP_OPCODE_ERROR
Error.
Definition: tftp_common.h:56
TftpRrqPacket
Definition: tftp_common.h:94
NetInterface * interface
Underlying network interface.
Definition: socket.h:248
#define FALSE
Definition: os_port.h:46
const SocketMsg SOCKET_DEFAULT_MSG
Definition: socket.c:52
size_t length
Actual length of the payload, in bytes.
Definition: socket.h:244
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
TftpWrqPacket
Definition: tftp_common.h:105
error_t
Error codes.
Definition: error.h:43
bool_t ipCompAddr(const IpAddr *ipAddr1, const IpAddr *ipAddr2)
Compare IP addresses.
Definition: ip.c:318
#define TFTP_SERVER_TIMEOUT
Definition: tftp_server.h:80
#define TFTP_SERVER_MAX_PACKET_SIZE
Definition: tftp_server.h:105
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:65
#define TFTP_SERVER_BLOCK_SIZE
Definition: tftp_server.h:94
#define NetInterface
Definition: net.h:40
IpAddr srcIpAddr
Source IP address.
Definition: socket.h:249
@ ERROR_END_OF_FILE
Definition: error.h:160
error_t socketReceiveFrom(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size, size_t *received, uint_t flags)
Receive a datagram from a connectionless socket.
Definition: socket.c:1746
error_t socketReceiveMsg(Socket *socket, SocketMsg *message, uint_t flags)
Receive a message from a connectionless socket.
Definition: socket.c:1926
@ TFTP_OPCODE_DATA
Data.
Definition: tftp_common.h:54
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1377
@ TFTP_STATE_OPEN
Definition: tftp_server.h:128
@ TFTP_STATE_READING
Definition: tftp_server.h:129
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
#define TFTP_SERVER_MAX_CONNECTIONS
Definition: tftp_server.h:59
@ TFTP_STATE_WRITE_COMPLETE
Definition: tftp_server.h:132
@ TFTP_STATE_READ_COMPLETE
Definition: tftp_server.h:131
TftpAckPacket
Definition: tftp_common.h:128
void tftpServerTick(TftpServerContext *context)
Handle periodic operations.
#define socketBindToInterface
Definition: net_legacy.h:193
uint32_t systime_t
System time.
void tftpServerProcessAckPacket(TftpClientConnection *connection, const TftpAckPacket *ackPacket, size_t length)
Process incoming ACK packet.
#define ntohs(value)
Definition: cpu_endian.h:421
@ TFTP_STATE_CLOSED
Definition: tftp_server.h:127
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
error_t tftpServerSendAckPacket(TftpClientConnection *connection)
Send ACK packet.
void tftpServerAcceptRequest(TftpServerContext *context)
Accept connection request.
uint32_t time
error_t tftpServerSendDataPacket(TftpClientConnection *connection)
Send DATA packet.
#define HTONS(value)
Definition: cpu_endian.h:410
@ ERROR_READ_FAILED
Definition: error.h:224
@ ERROR_WRITE_FAILED
Definition: error.h:223
Socket * socketOpenEx(NetContext *context, uint_t type, uint_t protocol)
Create a socket.
Definition: socket.c:146
#define Socket
Definition: socket.h:36
#define TftpClientConnection
Definition: tftp_server.h:109
Helper functions for TFTP server.
size_t size
Size of the payload, in bytes.
Definition: socket.h:243
TftpDataPacket
Definition: tftp_common.h:117
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
void tftpServerProcessDataPacket(TftpClientConnection *connection, const TftpDataPacket *dataPacket, size_t length)
Process incoming DATA packet.
#define LOAD16BE(p)
Definition: cpu_endian.h:186
#define osMemset(p, value, length)
Definition: os_port.h:141
TCP/IP stack core.
#define osStrcpy(s1, s2)
Definition: os_port.h:213
uint16_t srcPort
Source port.
Definition: socket.h:250
#define TFTP_SERVER_FINAL_DELAY
Definition: tftp_server.h:87
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
systime_t osGetSystemTime(void)
Retrieve system time.
@ TFTP_OPCODE_RRQ
Read request.
Definition: tftp_common.h:52