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