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