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