1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/examples/gnrc_tftp/tftp_client.c
2016-01-05 14:59:34 +01:00

217 lines
6.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 client
*
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "kernel.h"
#include "net/gnrc/tftp.h"
static const char *_tftp_default_host = "::1";
/* default server text which can be received */
static const char _tftp_client_hello[] = "Hello,\n"
"\n"
"Client text would also need to exist to be able to put data.\n"
"\n"
"Enjoy the RIOT-OS\n";
static tftp_action_t _tftp_action;
/**
* @brief called at every transaction start
*/
static bool _tftp_client_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_client: %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_client_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_client_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_WRITE) {
/* calculate the length of the data block to transfer */
if (offset + data_len > sizeof(_tftp_client_hello)) {
data_len -= (offset + data_len) - sizeof(_tftp_client_hello);
}
/* copy the block to the output buffer */
memcpy(data, _tftp_client_hello + offset, data_len);
}
else {
/* we received a data block which we output to the console */
printf("\n -- CLIENT DATA --\n%.*s\n -- CLIENT 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_client_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_client: %s: %s\n", cause, msg);
}
static int _tftp_client_cmd(int argc, char * *argv)
{
ipv6_addr_t ip;
const char *file_name = argv[2];
tftp_mode_t mode = TTM_OCTET;
bool use_options = true;
ipv6_addr_from_str(&ip, _tftp_default_host);
if (argc >= 3 && argc <= 6) {
/* decode the action */
if (strcmp(argv[1], "get") == 0) {
_tftp_action = TFTP_READ;
}
else if (strcmp(argv[1], "put") == 0) {
_tftp_action = TFTP_WRITE;
}
else {
return -1;
}
/* get the transfer mode */
if (argc >= 4) {
if (strcmp(argv[3], "octet") == 0) {
mode = TTM_OCTET;
}
else if (strcmp(argv[3], "ascii") == 0) {
mode = TTM_ASCII;
}
else if (strcmp(argv[3], "mail") == 0) {
mode = TTM_MAIL;
}
else {
puts("tftp: couldn't parse the TFTP transfer mode");
return -1;
}
}
/* decode if we must use the TFTP option extension or not */
if (argc >= 5) {
if (strcmp(argv[4], "0") == 0) {
use_options = false;
}
else if (strcmp(argv[4], "1") == 0) {
use_options = true;
}
else {
puts("tftp: invalid options choose 0 or 1");
return -1;
}
}
/* decode the address */
if (argc >= 6) {
if (!ipv6_addr_from_str(&ip, argv[5])) {
puts("tftp: invalid IP address");
return -1;
}
}
}
else {
return -1;
}
if (_tftp_action == TFTP_READ) {
puts("tftp: starting read request");
gnrc_tftp_client_read(&ip, file_name, mode, _tftp_client_data_cb,
_tftp_client_start_cb, _tftp_client_stop_cb, use_options);
}
else if (_tftp_action == TFTP_WRITE) {
puts("tftp: starting write request");
gnrc_tftp_client_write(&ip, file_name, mode, _tftp_client_data_cb,
sizeof(_tftp_client_hello), _tftp_client_stop_cb, use_options);
}
return 0;
}
/**
* @brief start the TFTP server by creating a thread
*/
int tftp_client_cmd(int argc, char * *argv)
{
if (_tftp_client_cmd(argc, argv) < 0) {
printf("usage: %s <action[get|put]> <file_name> <mode[ascii | octet(default) | mail]>\n"
"\t<use_options[1 (default) | 0]> <addr(default: ::1)>\n", argv[0]);
}
return 0;
}