tftp_server.c
Go to the documentation of this file.
1 /**
2  * @file tftp_server.c
3  * @brief TFTP server
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 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  * @section Description
28  *
29  * TFTP is a very simple protocol used to transfer files. Refer to the
30  * following RFCs for complete details:
31  * - RFC 1123: Requirements for Internet Hosts
32  * - RFC 1350: The TFTP Protocol (Revision 2)
33  * - RFC 1782: TFTP Option Extension
34  * - RFC 1783: TFTP Blocksize Option
35  * - RFC 1784: TFTP Timeout Interval and Transfer Size Options
36  *
37  * @author Oryx Embedded SARL (www.oryx-embedded.com)
38  * @version 2.4.0
39  **/
40 
41 //Switch to the appropriate trace level
42 #define TRACE_LEVEL TFTP_TRACE_LEVEL
43 
44 //Dependencies
45 #include "tftp/tftp_server.h"
46 #include "tftp/tftp_server_misc.h"
47 #include "debug.h"
48 
49 //Check TCP/IP stack configuration
50 #if (TFTP_SERVER_SUPPORT == ENABLED)
51 
52 
53 /**
54  * @brief Initialize settings with default values
55  * @param[out] settings Structure that contains TFTP server settings
56  **/
57 
59 {
60  //Default task parameters
61  settings->task = OS_TASK_DEFAULT_PARAMS;
64 
65  //The TFTP server is not bound to any interface
66  settings->interface = NULL;
67 
68  //TFTP port number
69  settings->port = TFTP_PORT;
70 
71  //Open file callback function
72  settings->openFileCallback = NULL;
73  //Write file callback function
74  settings->writeFileCallback = NULL;
75  //Read file callback function
76  settings->readFileCallback = NULL;
77  //Close file callback function
78  settings->closeFileCallback = NULL;
79 }
80 
81 
82 /**
83  * @brief TFTP server initialization
84  * @param[in] context Pointer to the TFTP server context
85  * @param[in] settings TFTP server specific settings
86  * @return Error code
87  **/
88 
90  const TftpServerSettings *settings)
91 {
92  error_t error;
93 
94  //Debug message
95  TRACE_INFO("Initializing TFTP server...\r\n");
96 
97  //Ensure the parameters are valid
98  if(context == NULL || settings == NULL)
100 
101  //Clear the TFTP server context
102  osMemset(context, 0, sizeof(TftpServerContext));
103 
104  //Initialize task parameters
105  context->taskParams = settings->task;
106  context->taskId = OS_INVALID_TASK_ID;
107 
108  //Save user settings
109  context->settings = *settings;
110 
111  //Initialize status code
112  error = NO_ERROR;
113 
114  //Create an event object to poll the state of sockets
115  if(!osCreateEvent(&context->event))
116  {
117  //Failed to create event
118  error = ERROR_OUT_OF_RESOURCES;
119  }
120 
121  //Check status code
122  if(error)
123  {
124  //Clean up side effects
125  tftpServerDeinit(context);
126  }
127 
128  //Return status code
129  return error;
130 }
131 
132 
133 /**
134  * @brief Start TFTP server
135  * @param[in] context Pointer to the TFTP server context
136  * @return Error code
137  **/
138 
140 {
141  error_t error;
142 
143  //Make sure the TFTP server context is valid
144  if(context == NULL)
146 
147  //Debug message
148  TRACE_INFO("Starting TFTP server...\r\n");
149 
150  //Make sure the TFTP server is not already running
151  if(context->running)
152  return ERROR_ALREADY_RUNNING;
153 
154  //Start of exception handling block
155  do
156  {
157  //Open a UDP socket
159  //Failed to open socket?
160  if(context->socket == NULL)
161  {
162  //Report an error
163  error = ERROR_OPEN_FAILED;
164  break;
165  }
166 
167  //Associate the socket with the relevant interface
168  error = socketBindToInterface(context->socket,
169  context->settings.interface);
170  //Unable to bind the socket to the desired interface?
171  if(error)
172  break;
173 
174  //The TFTP server listens for connection requests on port 69
175  error = socketBind(context->socket, &IP_ADDR_ANY, context->settings.port);
176  //Unable to bind the socket to the desired port?
177  if(error)
178  break;
179 
180  //Start the TFTP server
181  context->stop = FALSE;
182  context->running = TRUE;
183 
184  //Create a task
185  context->taskId = osCreateTask("TFTP Server", (OsTaskCode) tftpServerTask,
186  context, &context->taskParams);
187 
188  //Failed to create task?
189  if(context->taskId == OS_INVALID_TASK_ID)
190  {
191  //Report an error
192  error = ERROR_OUT_OF_RESOURCES;
193  break;
194  }
195 
196  //End of exception handling block
197  } while(0);
198 
199  //Any error to report?
200  if(error)
201  {
202  //Clean up side effects
203  context->running = FALSE;
204 
205  //Close the UDP socket
206  socketClose(context->socket);
207  context->socket = NULL;
208  }
209 
210  //Return status code
211  return error;
212 }
213 
214 
215 /**
216  * @brief Stop TFTP server
217  * @param[in] context Pointer to the TFTP server context
218  * @return Error code
219  **/
220 
222 {
223  uint_t i;
224 
225  //Make sure the TFTP server context is valid
226  if(context == NULL)
228 
229  //Debug message
230  TRACE_INFO("Stopping TFTP server...\r\n");
231 
232  //Check whether the TFTP server is running
233  if(context->running)
234  {
235  //Stop the TFTP server
236  context->stop = TRUE;
237  //Send a signal to the task to abort any blocking operation
238  osSetEvent(&context->event);
239 
240  //Wait for the task to terminate
241  while(context->running)
242  {
243  osDelayTask(1);
244  }
245 
246  //Loop through the connection table
247  for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
248  {
249  //Close client connection
250  tftpServerCloseConnection(&context->connection[i]);
251  }
252 
253  //Close the UDP socket
254  socketClose(context->socket);
255  context->socket = NULL;
256  }
257 
258  //Successful processing
259  return NO_ERROR;
260 }
261 
262 
263 /**
264  * @brief TFTP server task
265  * @param[in] context Pointer to the TFTP server context
266  **/
267 
269 {
270  error_t error;
271  uint_t i;
272  TftpClientConnection *connection;
273 
274 #if (NET_RTOS_SUPPORT == ENABLED)
275  //Task prologue
276  osEnterTask();
277 
278  //Process events
279  while(1)
280  {
281 #endif
282  //Clear event descriptor set
283  osMemset(context->eventDesc, 0, sizeof(context->eventDesc));
284 
285  //Specify the events the application is interested in
286  for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
287  {
288  //Point to the structure describing the current connection
289  connection = &context->connection[i];
290 
291  //Loop through active connections only
292  if(connection->state != TFTP_STATE_CLOSED)
293  {
294  //Wait for a packet to be received
295  context->eventDesc[i].socket = connection->socket;
296  context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY;
297  }
298  }
299 
300  //The TFTP server listens for connection requests on port 69
301  context->eventDesc[i].socket = context->socket;
302  context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY;
303 
304  //Wait for one of the set of sockets to become ready to perform I/O
305  error = socketPoll(context->eventDesc, TFTP_SERVER_MAX_CONNECTIONS + 1,
306  &context->event, TFTP_SERVER_TICK_INTERVAL);
307 
308  //Check status code
309  if(error == NO_ERROR || error == ERROR_TIMEOUT ||
310  error == ERROR_WAIT_CANCELED)
311  {
312  //Stop request?
313  if(context->stop)
314  {
315  //Stop TFTP server operation
316  context->running = FALSE;
317  //Task epilogue
318  osExitTask();
319  //Kill ourselves
321  }
322 
323  //Event-driven processing
324  for(i = 0; i < TFTP_SERVER_MAX_CONNECTIONS; i++)
325  {
326  //Point to the structure describing the current connection
327  connection = &context->connection[i];
328 
329  //Loop through active connections only
330  if(connection->state != TFTP_STATE_CLOSED)
331  {
332  //Check whether a packet has been received
333  if((context->eventDesc[i].eventFlags & SOCKET_EVENT_RX_READY) != 0)
334  {
335  //Process incoming packet
336  tftpServerProcessPacket(context, connection);
337  }
338  }
339  }
340 
341  //Any connection request received on port 69?
342  if((context->eventDesc[i].eventFlags & SOCKET_EVENT_RX_READY) != 0)
343  {
344  //Accept connection request
345  tftpServerAcceptRequest(context);
346  }
347  }
348 
349  //Handle periodic operations
350  tftpServerTick(context);
351 
352 #if (NET_RTOS_SUPPORT == ENABLED)
353  }
354 #endif
355 }
356 
357 
358 /**
359  * @brief Release TFTP server context
360  * @param[in] context Pointer to the TFTP server context
361  **/
362 
364 {
365  //Make sure the TFTP server context is valid
366  if(context != NULL)
367  {
368  //Free previously allocated resources
369  osDeleteEvent(&context->event);
370 
371  //Clear TFTP server context
372  osMemset(context, 0, sizeof(TftpServerContext));
373  }
374 }
375 
376 #endif
unsigned int uint_t
Definition: compiler_port.h:50
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
error_t
Error codes.
Definition: error.h:43
@ ERROR_WAIT_CANCELED
Definition: error.h:73
@ ERROR_ALREADY_RUNNING
Definition: error.h:292
@ ERROR_TIMEOUT
Definition: error.h:95
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
const IpAddr IP_ADDR_ANY
Definition: ip.c:51
#define socketBindToInterface
Definition: net_legacy.h:193
#define osMemset(p, value, length)
Definition: os_port.h:135
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osDeleteEvent(OsEvent *event)
Delete an event object.
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
void osDelayTask(systime_t delay)
Delay routine.
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
void osDeleteTask(OsTaskId taskId)
Delete a task.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void(* OsTaskCode)(void *arg)
Task routine.
#define osEnterTask()
#define OS_SELF_TASK_ID
#define OS_INVALID_TASK_ID
#define osExitTask()
error_t socketBind(Socket *socket, const IpAddr *localIpAddr, uint16_t localPort)
Associate a local address with a socket.
Definition: socket.c:778
error_t socketPoll(SocketEventDesc *eventDesc, uint_t size, OsEvent *extEvent, systime_t timeout)
Wait for one of a set of sockets to become ready to perform I/O.
Definition: socket.c:1592
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:1517
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:101
@ SOCKET_TYPE_DGRAM
Definition: socket.h:86
@ SOCKET_EVENT_RX_READY
Definition: socket.h:169
TFTP server settings.
Definition: tftp_server.h:172
OsTaskParameters task
Task parameters.
Definition: tftp_server.h:173
TftpServerCloseFileCallback closeFileCallback
Close file callback function.
Definition: tftp_server.h:179
uint16_t port
TFTP port number.
Definition: tftp_server.h:175
TftpServerWriteFileCallback writeFileCallback
Write file callback function.
Definition: tftp_server.h:177
TftpServerOpenFileCallback openFileCallback
Open file callback function.
Definition: tftp_server.h:176
TftpServerReadFileCallback readFileCallback
Read file callback function.
Definition: tftp_server.h:178
NetInterface * interface
Underlying network interface.
Definition: tftp_server.h:174
#define TFTP_PORT
Definition: tftp_common.h:38
error_t tftpServerInit(TftpServerContext *context, const TftpServerSettings *settings)
TFTP server initialization.
Definition: tftp_server.c:89
void tftpServerGetDefaultSettings(TftpServerSettings *settings)
Initialize settings with default values.
Definition: tftp_server.c:58
error_t tftpServerStart(TftpServerContext *context)
Start TFTP server.
Definition: tftp_server.c:139
void tftpServerTask(TftpServerContext *context)
TFTP server task.
Definition: tftp_server.c:268
error_t tftpServerStop(TftpServerContext *context)
Stop TFTP server.
Definition: tftp_server.c:221
void tftpServerDeinit(TftpServerContext *context)
Release TFTP server context.
Definition: tftp_server.c:363
TFTP server.
#define TFTP_SERVER_MAX_CONNECTIONS
Definition: tftp_server.h:59
#define TftpClientConnection
Definition: tftp_server.h:109
#define TFTP_SERVER_PRIORITY
Definition: tftp_server.h:54
#define TftpServerContext
Definition: tftp_server.h:113
#define TFTP_SERVER_STACK_SIZE
Definition: tftp_server.h:47
@ TFTP_STATE_CLOSED
Definition: tftp_server.h:127
#define TFTP_SERVER_TICK_INTERVAL
Definition: tftp_server.h:66
void tftpServerProcessPacket(TftpServerContext *context, TftpClientConnection *connection)
Process incoming packet.
void tftpServerAcceptRequest(TftpServerContext *context)
Accept connection request.
void tftpServerCloseConnection(TftpClientConnection *connection)
Close client connection.
void tftpServerTick(TftpServerContext *context)
Handle periodic operations.
Helper functions for TFTP server.