mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
192 lines
5.0 KiB
C
192 lines
5.0 KiB
C
/*
|
|
* Copyright (C) 2015 Engineering-Spirit
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup examples
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Demonstrating the sending and receiving of data via the TFTP server
|
|
*
|
|
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "thread.h"
|
|
#include "net/gnrc/tftp.h"
|
|
|
|
/* the message queues */
|
|
#define TFTP_QUEUE_SIZE (4)
|
|
static msg_t _tftp_msg_queue[TFTP_QUEUE_SIZE];
|
|
|
|
/* allocate the stack */
|
|
char _tftp_stack[THREAD_STACKSIZE_MAIN + THREAD_EXTRA_STACKSIZE_PRINTF];
|
|
|
|
/* default server text which can be received */
|
|
static const char _tftp_server_hello[] = "Hello world,\n"
|
|
"\n"
|
|
"Welcome to the wonderful world of IoT and embedded systems.\n"
|
|
"\n"
|
|
"Enjoy the RIOT-OS\n";
|
|
|
|
static tftp_action_t _tftp_action;
|
|
|
|
/**
|
|
* @brief called at every transcation start
|
|
*/
|
|
static bool _tftp_server_start_cb(tftp_action_t action, tftp_mode_t mode,
|
|
const char *file_name, size_t *len)
|
|
{
|
|
/* translate the mode */
|
|
const char *str_mode = "ascii";
|
|
|
|
if (mode == TTM_OCTET) {
|
|
str_mode = "bin";
|
|
}
|
|
else if (mode == TTM_MAIL) {
|
|
str_mode = "mail";
|
|
}
|
|
|
|
/* translate the action */
|
|
const char *str_action = "read";
|
|
if (action == TFTP_WRITE) {
|
|
str_action = "write";
|
|
}
|
|
|
|
/* display the action being performed */
|
|
printf("tftp_server: %s %s %s:%lu\n", str_mode, str_action, file_name, (unsigned long)*len);
|
|
|
|
/* return the length of the text, if this is an read action */
|
|
if (action == TFTP_READ) {
|
|
*len = sizeof(_tftp_server_hello);
|
|
}
|
|
|
|
/* remember the action of the current transfer */
|
|
_tftp_action = action;
|
|
|
|
/* we accept the transfer to take place so we return true */
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief called to get or put data, depending on the mode received by `_tftp_start_cb(action, ...)`
|
|
*/
|
|
static int _tftp_server_data_cb(uint32_t offset, void *data, size_t data_len)
|
|
{
|
|
char *c = (char *) data;
|
|
|
|
/* if we are reading return the part of the data that is being requested */
|
|
if (_tftp_action == TFTP_READ) {
|
|
/* calculate the length of the data block to transfer */
|
|
if (offset + data_len > sizeof(_tftp_server_hello)) {
|
|
data_len -= (offset + data_len) - sizeof(_tftp_server_hello);
|
|
}
|
|
|
|
/* copy the block to the output buffer */
|
|
memcpy(data, _tftp_server_hello + offset, data_len);
|
|
}
|
|
else {
|
|
/* we received a data block which we output to the console */
|
|
printf("\n -- SERVER DATA --\n%.*s\n -- SERVER DATA --\n", (int)data_len, c);
|
|
}
|
|
|
|
/* return the length of the data block */
|
|
return data_len;
|
|
}
|
|
|
|
/**
|
|
* @brief the transfer has stopped, see the event argument to determined if it was successful
|
|
* or not.
|
|
*/
|
|
static void _tftp_server_stop_cb(tftp_event_t event, const char *msg)
|
|
{
|
|
/* decode the stop event received */
|
|
const char *cause = "UNKOWN";
|
|
|
|
if (event == TFTP_SUCCESS) {
|
|
cause = "SUCCESS";
|
|
}
|
|
else if (event == TFTP_PEER_ERROR) {
|
|
cause = "ERROR From Client";
|
|
}
|
|
else if (event == TFTP_INTERN_ERROR) {
|
|
cause = "ERROR Internal Server Error";
|
|
}
|
|
|
|
/* print the transfer result to the console */
|
|
printf("tftp_server: %s: %s\n", cause, (msg == NULL) ? "NULL" : msg);
|
|
}
|
|
|
|
/**
|
|
* @brief the TFTP server thread
|
|
*/
|
|
void *tftp_server_wrapper(void *arg)
|
|
{
|
|
(void)arg;
|
|
|
|
/* A message queue is needed to register for incoming packets */
|
|
msg_init_queue(_tftp_msg_queue, TFTP_QUEUE_SIZE);
|
|
|
|
/* inform the user */
|
|
puts("tftp_server: Starting TFTP service at port 69");
|
|
|
|
/* run the TFTP server */
|
|
gnrc_tftp_server(_tftp_server_data_cb, _tftp_server_start_cb, _tftp_server_stop_cb, true);
|
|
|
|
/* the TFTP server has been stopped */
|
|
puts("tftp_server: Stopped TFTP service");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief start the TFTP server by creating a thread
|
|
*/
|
|
void tftp_server_start(void)
|
|
{
|
|
thread_create(_tftp_stack, sizeof(_tftp_stack),
|
|
1, THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
|
|
tftp_server_wrapper, NULL, "TFTP Server");
|
|
}
|
|
|
|
/**
|
|
* @brief stop the TFTP server by sending a message to the thread
|
|
*/
|
|
void tftp_server_stop(void)
|
|
{
|
|
gnrc_tftp_server_stop();
|
|
}
|
|
|
|
int tftp_server_cmd(int argc, char * *argv)
|
|
{
|
|
switch (argc) {
|
|
case 2:
|
|
if (strcmp(argv[1], "start") == 0) {
|
|
tftp_server_start();
|
|
return 0;
|
|
}
|
|
else if (strcmp(argv[1], "stop") == 0) {
|
|
tftp_server_stop();
|
|
return 0;
|
|
}
|
|
/* falls through */
|
|
|
|
default:
|
|
printf("usage: %s [start|stop]\n", argv[0]);
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|