解决一个擦除的bug
This commit is contained in:
21
Drivers/BSP/NET/lftpd/LICENSE.txt
Normal file
21
Drivers/BSP/NET/lftpd/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Jason von Nieda <jason@vonnieda.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
626
Drivers/BSP/NET/lftpd/lftpd.c
Normal file
626
Drivers/BSP/NET/lftpd/lftpd.c
Normal file
@@ -0,0 +1,626 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "lftpd.h"
|
||||
#include "private/lftpd_status.h"
|
||||
#include "private/lftpd_inet.h"
|
||||
#include "private/lftpd_log.h"
|
||||
#include "private/lftpd_string.h"
|
||||
#include "private/lftpd_io.h"
|
||||
#include "net_socket.h"
|
||||
#include "net_config.h"
|
||||
#include "ff.h"
|
||||
|
||||
typedef struct {
|
||||
const char *command;
|
||||
int (*handler)(lftpd_client_t *client, const char *arg);
|
||||
} command_t;
|
||||
|
||||
static int cmd_cwd(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_dele(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_epsv(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_feat(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_list(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_nlst(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_noop(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_pass(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_pasv(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_pwd(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_quit(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_retr(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_size(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_stor(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_syst(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_type(lftpd_client_t *client, const char *arg);
|
||||
static int cmd_user(lftpd_client_t *client, const char *arg);
|
||||
|
||||
static command_t commands[] = {
|
||||
{ "CWD", cmd_cwd },
|
||||
{ "DELE", cmd_dele },
|
||||
{ "EPSV", cmd_epsv },
|
||||
{ "FEAT", cmd_feat },
|
||||
{ "LIST", cmd_list },
|
||||
{ "NLST", cmd_nlst },
|
||||
{ "NOOP", cmd_noop },
|
||||
{ "PASS", cmd_pass },
|
||||
{ "PASV", cmd_pasv },
|
||||
{ "PWD", cmd_pwd },
|
||||
{ "QUIT", cmd_quit },
|
||||
{ "RETR", cmd_retr },
|
||||
{ "SIZE", cmd_size },
|
||||
{ "STOR", cmd_stor },
|
||||
{ "SYST", cmd_syst },
|
||||
{ "TYPE", cmd_type },
|
||||
{ "USER", cmd_user },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
static int send_response(int socket, int code, bool include_code,
|
||||
bool multiline_start, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char message[256];
|
||||
char response[512];
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(message, sizeof(message), format, args);
|
||||
va_end(args);
|
||||
|
||||
if (include_code) {
|
||||
if (multiline_start) {
|
||||
snprintf(response, sizeof(response), "%d-%s%s", code, message, CRLF);
|
||||
} else {
|
||||
snprintf(response, sizeof(response), "%d %s%s", code, message, CRLF);
|
||||
}
|
||||
} else {
|
||||
snprintf(response, sizeof(response), "%s%s", message, CRLF);
|
||||
}
|
||||
|
||||
return lftpd_inet_write_string(socket, response);
|
||||
}
|
||||
|
||||
#define send_simple_response(socket, code, format, ...) \
|
||||
send_response(socket, code, true, false, format, ##__VA_ARGS__)
|
||||
|
||||
#define send_multiline_response_begin(socket, code, format, ...) \
|
||||
send_response(socket, code, true, true, format, ##__VA_ARGS__)
|
||||
|
||||
#define send_multiline_response_line(socket, format, ...) \
|
||||
send_response(socket, 0, false, false, format, ##__VA_ARGS__)
|
||||
|
||||
#define send_multiline_response_end(socket, code, format, ...) \
|
||||
send_response(socket, code, true, false, format, ##__VA_ARGS__)
|
||||
|
||||
static int send_list(int socket, const char *path)
|
||||
{
|
||||
static const char *directory_format = "drw-rw-rw- 1 owner group %13lu Jan 01 1970 %s";
|
||||
static const char *file_format = "-rw-rw-rw- 1 owner group %13lu Jan 01 1970 %s";
|
||||
|
||||
void *dp = lftpd_io_opendir(path);
|
||||
if (dp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char name[256];
|
||||
uint32_t size;
|
||||
int is_dir;
|
||||
|
||||
while (lftpd_io_readdir(dp, name, sizeof(name), &size, &is_dir) == 0) {
|
||||
if (is_dir) {
|
||||
send_multiline_response_line(socket, directory_format,
|
||||
(unsigned long)size, name);
|
||||
} else {
|
||||
send_multiline_response_line(socket, file_format,
|
||||
(unsigned long)size, name);
|
||||
}
|
||||
}
|
||||
|
||||
lftpd_io_closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_nlst(int socket, const char *path)
|
||||
{
|
||||
void *dp = lftpd_io_opendir(path);
|
||||
if (dp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char name[256];
|
||||
uint32_t size;
|
||||
int is_dir;
|
||||
|
||||
while (lftpd_io_readdir(dp, name, sizeof(name), &size, &is_dir) == 0) {
|
||||
if (!is_dir) {
|
||||
send_multiline_response_line(socket, name);
|
||||
}
|
||||
}
|
||||
|
||||
lftpd_io_closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_file(int socket, const char *path)
|
||||
{
|
||||
int fh = lftpd_io_open_read(path);
|
||||
if (fh < 0) {
|
||||
lftpd_log_error("failed to open file for read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char buffer[1024];
|
||||
int read_len;
|
||||
|
||||
while ((read_len = lftpd_io_read(fh, buffer, sizeof(buffer))) > 0) {
|
||||
unsigned char *p = buffer;
|
||||
while (read_len > 0) {
|
||||
int write_len = lftpd_inet_write(socket, p, read_len);
|
||||
if (write_len < 0) {
|
||||
lftpd_log_error("write error");
|
||||
lftpd_io_close(fh);
|
||||
return -1;
|
||||
}
|
||||
p += write_len;
|
||||
read_len -= write_len;
|
||||
}
|
||||
}
|
||||
|
||||
lftpd_io_close(fh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int receive_file(int socket, const char *path)
|
||||
{
|
||||
int fh = lftpd_io_open_write(path);
|
||||
if (fh < 0) {
|
||||
lftpd_log_error("failed to open file for write");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char buffer[1024];
|
||||
int err;
|
||||
|
||||
while ((err = lftpd_inet_read(socket, buffer, sizeof(buffer))) > 0) {
|
||||
if (lftpd_io_write(fh, buffer, err) != err) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lftpd_io_close(fh);
|
||||
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_cwd(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (arg == NULL || strlen(arg) == 0) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *path = lftpd_io_canonicalize_path(client->directory, arg);
|
||||
|
||||
uint32_t size;
|
||||
int is_dir;
|
||||
if (lftpd_io_stat(path, &size, &is_dir) != 0) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!is_dir) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(client->directory, path, sizeof(client->directory) - 1);
|
||||
client->directory[sizeof(client->directory) - 1] = '\0';
|
||||
free(path);
|
||||
|
||||
send_simple_response(client->socket, 250, STATUS_250);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_dele(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (arg == NULL || strlen(arg) == 0) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *path = lftpd_io_canonicalize_path(client->directory, arg);
|
||||
|
||||
uint32_t size;
|
||||
int is_dir;
|
||||
if (lftpd_io_stat(path, &size, &is_dir) != 0) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_dir) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lftpd_io_unlink(path);
|
||||
free(path);
|
||||
send_simple_response(client->socket, 250, STATUS_250);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_epsv(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
int listener_socket = lftpd_inet_listen(0);
|
||||
if (listener_socket < 0) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int port = lftpd_inet_get_socket_port(listener_socket);
|
||||
|
||||
send_simple_response(client->socket, 229, STATUS_229, port);
|
||||
|
||||
lftpd_log_debug("waiting for data port connection on port %d...", port);
|
||||
int data_sock = lftpd_inet_accept(listener_socket);
|
||||
if (data_sock < 0) {
|
||||
lftpd_log_error("error accepting client socket");
|
||||
lftpd_inet_close(listener_socket);
|
||||
return -1;
|
||||
}
|
||||
lftpd_log_debug("data port connection received...");
|
||||
|
||||
client->data_socket = data_sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_feat(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_multiline_response_begin(client->socket, 211, STATUS_211);
|
||||
send_multiline_response_line(client->socket, "EPSV");
|
||||
send_multiline_response_line(client->socket, "PASV");
|
||||
send_multiline_response_line(client->socket, "SIZE");
|
||||
send_multiline_response_line(client->socket, "NLST");
|
||||
send_multiline_response_end(client->socket, 211, STATUS_211);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_list(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (client->data_socket == -1) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
int err = send_list(client->data_socket, client->directory);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
send_simple_response(client->socket, 226, STATUS_226);
|
||||
} else {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_nlst(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (client->data_socket == -1) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
int err = send_nlst(client->data_socket, client->directory);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
send_simple_response(client->socket, 226, STATUS_226);
|
||||
} else {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_noop(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 200, STATUS_200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_pass(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 230, STATUS_230);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_pasv(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
int listener_socket = lftpd_inet_listen(0);
|
||||
if (listener_socket < 0) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int port = lftpd_inet_get_socket_port(listener_socket);
|
||||
|
||||
{
|
||||
struct net_sockaddr_in local_addr;
|
||||
int addrlen = sizeof(local_addr);
|
||||
int err = net_getsockname(client->socket,
|
||||
(struct net_sockaddr *)&local_addr, &addrlen);
|
||||
if (err != 0) {
|
||||
lftpd_log_error("error getting client IP info");
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
lftpd_inet_close(listener_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t ip = net_htonl(local_addr.sin_addr.s_addr);
|
||||
send_simple_response(client->socket, 227, STATUS_227,
|
||||
(ip >> 24) & 0xff,
|
||||
(ip >> 16) & 0xff,
|
||||
(ip >> 8) & 0xff,
|
||||
(ip >> 0) & 0xff,
|
||||
(port >> 8) & 0xff, (port >> 0) & 0xff);
|
||||
}
|
||||
|
||||
lftpd_log_debug("waiting for data port connection on port %d...", port);
|
||||
int data_sock = lftpd_inet_accept(listener_socket);
|
||||
if (data_sock < 0) {
|
||||
lftpd_log_error("error accepting client socket");
|
||||
lftpd_inet_close(listener_socket);
|
||||
return -1;
|
||||
}
|
||||
lftpd_log_debug("data port connection received...");
|
||||
|
||||
client->data_socket = data_sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_pwd(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 257, "\"%s\"", client->directory);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_quit(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 221, STATUS_221);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cmd_retr(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (client->data_socket == -1) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
char *path = lftpd_io_canonicalize_path(client->directory, arg);
|
||||
lftpd_log_debug("send '%s'", path);
|
||||
int err = send_file(client->data_socket, path);
|
||||
free(path);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
send_simple_response(client->socket, 226, STATUS_226);
|
||||
} else {
|
||||
send_simple_response(client->socket, 450, STATUS_450);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_size(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (arg == NULL) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *path = lftpd_io_canonicalize_path(client->directory, arg);
|
||||
lftpd_log_debug("size %s", path);
|
||||
|
||||
uint32_t size;
|
||||
int is_dir;
|
||||
if (lftpd_io_stat(path, &size, &is_dir) == 0 && !is_dir) {
|
||||
send_simple_response(client->socket, 213, "%lu", (unsigned long)size);
|
||||
} else {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
}
|
||||
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_stor(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (client->data_socket == -1) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
char *path = lftpd_io_canonicalize_path(client->directory, arg);
|
||||
lftpd_log_debug("receive '%s'", path);
|
||||
int err = receive_file(client->data_socket, path);
|
||||
free(path);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
send_simple_response(client->socket, 226, STATUS_226);
|
||||
} else {
|
||||
send_simple_response(client->socket, 450, STATUS_450);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_syst(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 215, "UNIX Type: L8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_type(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 200, STATUS_200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_user(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
send_simple_response(client->socket, 230, STATUS_230);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_control_channel(lftpd_client_t *client)
|
||||
{
|
||||
int err = send_simple_response(client->socket, 220, STATUS_220);
|
||||
if (err != 0) {
|
||||
lftpd_log_error("error sending welcome message");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
char read_buffer[512];
|
||||
|
||||
while (err == 0) {
|
||||
int line_len = lftpd_inet_read_line(client->socket, read_buffer,
|
||||
sizeof(read_buffer));
|
||||
if (line_len != 0) {
|
||||
lftpd_log_error("error reading next command");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int index;
|
||||
char *p = strchr(read_buffer, ' ');
|
||||
if (p != NULL) {
|
||||
index = (int)(p - read_buffer);
|
||||
} else {
|
||||
index = (int)strlen(read_buffer);
|
||||
}
|
||||
|
||||
if (index >= 5) {
|
||||
err = send_simple_response(client->socket, 500, STATUS_500);
|
||||
continue;
|
||||
}
|
||||
|
||||
char command_tmp[4 + 1];
|
||||
memset(command_tmp, 0, sizeof(command_tmp));
|
||||
memcpy(command_tmp, read_buffer, (size_t)index);
|
||||
|
||||
for (int i = 0; command_tmp[i]; i++) {
|
||||
command_tmp[i] = (char)toupper((int)command_tmp[i]);
|
||||
}
|
||||
|
||||
bool matched = false;
|
||||
for (int i = 0; commands[i].command; i++) {
|
||||
if (strcmp(commands[i].command, command_tmp) == 0) {
|
||||
char arg_buf[512];
|
||||
const char *arg = NULL;
|
||||
|
||||
if (index < (int)strlen(read_buffer)) {
|
||||
strncpy(arg_buf, read_buffer + index + 1, sizeof(arg_buf) - 1);
|
||||
arg_buf[sizeof(arg_buf) - 1] = '\0';
|
||||
arg = lftpd_string_trim(arg_buf);
|
||||
}
|
||||
|
||||
err = commands[i].handler(client, arg);
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
send_simple_response(client->socket, 502, STATUS_502);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
lftpd_inet_close(client->socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
|
||||
{
|
||||
memset(lftpd, 0, sizeof(lftpd_t));
|
||||
|
||||
lftpd->directory = directory;
|
||||
lftpd->port = port;
|
||||
|
||||
while (true) {
|
||||
lftpd->server_socket = lftpd_inet_listen(port);
|
||||
if (lftpd->server_socket < 0) {
|
||||
lftpd_log_error("error creating listener");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
continue;
|
||||
}
|
||||
|
||||
lftpd_log_info("waiting for connection...");
|
||||
|
||||
int client_socket = lftpd_inet_accept(lftpd->server_socket);
|
||||
if (client_socket < 0) {
|
||||
lftpd_log_error("error accepting client socket");
|
||||
lftpd_inet_close(lftpd->server_socket);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char ip_str[16];
|
||||
struct net_sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
if (net_getsockname(client_socket,
|
||||
(struct net_sockaddr *)&addr, &addrlen) == 0) {
|
||||
net_inet_ntoa(addr.sin_addr.s_addr, ip_str);
|
||||
int remote_port = lftpd_inet_get_socket_port(client_socket);
|
||||
lftpd_log_info("connection received from %s:%d...",
|
||||
ip_str, remote_port);
|
||||
} else {
|
||||
lftpd_log_info("connection received...");
|
||||
}
|
||||
}
|
||||
|
||||
lftpd_client_t client;
|
||||
memset(&client, 0, sizeof(client));
|
||||
strncpy(client.directory, directory, sizeof(client.directory) - 1);
|
||||
client.directory[sizeof(client.directory) - 1] = '\0';
|
||||
client.socket = client_socket;
|
||||
client.data_socket = -1;
|
||||
|
||||
lftpd->client = &client;
|
||||
handle_control_channel(&client);
|
||||
lftpd->client = NULL;
|
||||
|
||||
/* standalone mode: socket was closed in handle_control_channel,
|
||||
* loop back to create a new listener */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_stop(lftpd_t *lftpd)
|
||||
{
|
||||
if (lftpd->server_socket >= 0) {
|
||||
lftpd_inet_close(lftpd->server_socket);
|
||||
}
|
||||
if (lftpd->client) {
|
||||
lftpd_inet_close(lftpd->client->socket);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
19
Drivers/BSP/NET/lftpd/lftpd.h
Normal file
19
Drivers/BSP/NET/lftpd/lftpd.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
char directory[256];
|
||||
int socket;
|
||||
int data_socket;
|
||||
} lftpd_client_t;
|
||||
|
||||
typedef struct {
|
||||
const char *directory;
|
||||
int port;
|
||||
int server_socket;
|
||||
lftpd_client_t *client;
|
||||
} lftpd_t;
|
||||
|
||||
int lftpd_start(const char *directory, int port, lftpd_t *lftpd);
|
||||
int lftpd_stop(lftpd_t *lftpd);
|
||||
161
Drivers/BSP/NET/lftpd/lftpd_inet.c
Normal file
161
Drivers/BSP/NET/lftpd/lftpd_inet.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#define DBG_TAG "[LFT_INET]"
|
||||
|
||||
#include "private/lftpd_inet.h"
|
||||
#include "dbg_log.h"
|
||||
#include "net_socket.h"
|
||||
#include <string.h>
|
||||
|
||||
int lftpd_inet_listen(int port)
|
||||
{
|
||||
int s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
DBG_ERROR("error creating listener socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct net_sockaddr_in addr;
|
||||
addr.sin_family = NET_AF_INET;
|
||||
addr.sin_port = net_htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = 0;
|
||||
|
||||
if (net_bind(s, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
DBG_ERROR("error binding listener port %d", port);
|
||||
net_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (net_listen(s, 0) < 0) {
|
||||
DBG_ERROR("error listening on socket");
|
||||
net_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int lftpd_inet_listen_multi(int port, int backlog)
|
||||
{
|
||||
int s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
DBG_ERROR("error creating multi listener socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct net_sockaddr_in addr;
|
||||
addr.sin_family = NET_AF_INET;
|
||||
addr.sin_port = net_htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = 0;
|
||||
|
||||
if (net_bind(s, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
DBG_ERROR("error binding multi listener port %d", port);
|
||||
net_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (net_listen(s, backlog) < 0) {
|
||||
DBG_ERROR("error listening on multi socket");
|
||||
net_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int lftpd_inet_get_socket_port(int socket)
|
||||
{
|
||||
struct net_sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
|
||||
if (net_getsockname(socket, (struct net_sockaddr *)&addr, &addrlen) < 0) {
|
||||
DBG_ERROR("error getting socket port number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)net_ntohs(addr.sin_port);
|
||||
}
|
||||
|
||||
int lftpd_inet_accept(int socket)
|
||||
{
|
||||
while (1) {
|
||||
int s = net_accept(socket, NULL, NULL);
|
||||
if (s >= 0) {
|
||||
return s;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len)
|
||||
{
|
||||
memset(buffer, 0, buffer_len);
|
||||
int total_read_len = 0;
|
||||
|
||||
while (total_read_len < (int)buffer_len) {
|
||||
int read_len = net_recv(socket,
|
||||
buffer + total_read_len,
|
||||
buffer_len - total_read_len - 1,
|
||||
0);
|
||||
if (read_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (read_len < 0) {
|
||||
return read_len;
|
||||
}
|
||||
|
||||
total_read_len += read_len;
|
||||
|
||||
char *p = strstr(buffer, "\r\n");
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lftpd_inet_write_string(int socket, const char *message)
|
||||
{
|
||||
const char *p = message;
|
||||
int length = (int)strlen(message);
|
||||
|
||||
while (length > 0) {
|
||||
int write_len = net_send(socket, p, length, 0);
|
||||
if (write_len < 0) {
|
||||
DBG_ERROR("write error");
|
||||
return write_len;
|
||||
}
|
||||
p += write_len;
|
||||
length -= write_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_inet_write(int socket, const void *buf, int len)
|
||||
{
|
||||
const char *p = (const char *)buf;
|
||||
int remaining = len;
|
||||
|
||||
while (remaining > 0) {
|
||||
int n = net_send(socket, p, remaining, 0);
|
||||
if (n < 0) {
|
||||
return n;
|
||||
}
|
||||
p += n;
|
||||
remaining -= n;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int lftpd_inet_read(int socket, void *buf, int len)
|
||||
{
|
||||
int n = net_recv(socket, buf, len, 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
int lftpd_inet_close(int socket)
|
||||
{
|
||||
return net_close(socket);
|
||||
}
|
||||
204
Drivers/BSP/NET/lftpd/lftpd_io.c
Normal file
204
Drivers/BSP/NET/lftpd/lftpd_io.c
Normal file
@@ -0,0 +1,204 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ff.h"
|
||||
#include "private/lftpd_io.h"
|
||||
|
||||
static int s_file_open = 0;
|
||||
static FIL s_ftp_file;
|
||||
|
||||
char *lftpd_io_canonicalize_path(const char *base, const char *name)
|
||||
{
|
||||
if (base == NULL) {
|
||||
base = "";
|
||||
}
|
||||
if (name == NULL) {
|
||||
name = "";
|
||||
}
|
||||
|
||||
char *path;
|
||||
if (name[0] == '/') {
|
||||
path = (char *)malloc(strlen(name) + 1);
|
||||
if (path == NULL) return NULL;
|
||||
strcpy(path, name);
|
||||
} else {
|
||||
size_t len = strlen(base) + 1 + strlen(name) + 1;
|
||||
path = (char *)malloc(len);
|
||||
if (path == NULL) return NULL;
|
||||
snprintf(path, len, "%s/%s", base, name);
|
||||
}
|
||||
|
||||
char *abs_path = (char *)malloc(strlen(path) + 2);
|
||||
if (abs_path == NULL) {
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
abs_path[0] = '\0';
|
||||
|
||||
char *p = path;
|
||||
while (*p != '\0') {
|
||||
while (*p == '/') p++;
|
||||
if (*p == '\0') break;
|
||||
|
||||
char *seg_start = p;
|
||||
while (*p != '\0' && *p != '/') p++;
|
||||
|
||||
char saved = *p;
|
||||
*p = '\0';
|
||||
|
||||
if (strcmp(seg_start, ".") == 0) {
|
||||
/* ignore */
|
||||
} else if (strcmp(seg_start, "..") == 0) {
|
||||
char *slash = strrchr(abs_path, '/');
|
||||
if (slash != NULL) {
|
||||
*slash = '\0';
|
||||
}
|
||||
} else {
|
||||
strcat(abs_path, "/");
|
||||
strcat(abs_path, seg_start);
|
||||
}
|
||||
|
||||
*p = saved;
|
||||
}
|
||||
free(path);
|
||||
|
||||
if (strlen(abs_path) == 0) {
|
||||
strcpy(abs_path, "/");
|
||||
}
|
||||
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
int lftpd_io_open_read(const char *path)
|
||||
{
|
||||
if (s_file_open) {
|
||||
return -1;
|
||||
}
|
||||
if (f_open(&s_ftp_file, path, FA_READ) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
s_file_open = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_io_open_write(const char *path)
|
||||
{
|
||||
if (s_file_open) {
|
||||
return -1;
|
||||
}
|
||||
if (f_open(&s_ftp_file, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
s_file_open = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_io_read(int handle, void *buf, int len)
|
||||
{
|
||||
(void)handle;
|
||||
UINT br;
|
||||
if (f_read(&s_ftp_file, buf, (UINT)len, &br) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
return (int)br;
|
||||
}
|
||||
|
||||
int lftpd_io_write(int handle, const void *buf, int len)
|
||||
{
|
||||
(void)handle;
|
||||
UINT bw;
|
||||
if (f_write(&s_ftp_file, buf, (UINT)len, &bw) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
if ((int)bw != len) {
|
||||
return -1;
|
||||
}
|
||||
return (int)bw;
|
||||
}
|
||||
|
||||
void lftpd_io_close(int handle)
|
||||
{
|
||||
(void)handle;
|
||||
if (s_file_open) {
|
||||
f_close(&s_ftp_file);
|
||||
s_file_open = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int lftpd_io_stat(const char *path, uint32_t *p_size, int *p_is_dir)
|
||||
{
|
||||
FILINFO fno;
|
||||
|
||||
if (f_stat(path, &fno) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p_size != NULL) {
|
||||
*p_size = (uint32_t)fno.fsize;
|
||||
}
|
||||
if (p_is_dir != NULL) {
|
||||
*p_is_dir = (fno.fattrib & AM_DIR) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_io_unlink(const char *path)
|
||||
{
|
||||
if (f_unlink(path) == FR_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *lftpd_io_opendir(const char *path)
|
||||
{
|
||||
DIR *dp = (DIR *)malloc(sizeof(DIR));
|
||||
if (dp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (f_opendir(dp, path) != FR_OK) {
|
||||
free(dp);
|
||||
return NULL;
|
||||
}
|
||||
return (void *)dp;
|
||||
}
|
||||
|
||||
int lftpd_io_readdir(void *dp, char *name, int name_max, uint32_t *p_size, int *p_is_dir)
|
||||
{
|
||||
FILINFO fno;
|
||||
FRESULT fr;
|
||||
|
||||
while (1) {
|
||||
fr = f_readdir((DIR *)dp, &fno);
|
||||
if (fr != FR_OK || fno.fname[0] == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (fno.fname[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(name, fno.fname, (size_t)(name_max - 1));
|
||||
name[name_max - 1] = '\0';
|
||||
|
||||
if (p_size != NULL) {
|
||||
*p_size = (uint32_t)fno.fsize;
|
||||
}
|
||||
if (p_is_dir != NULL) {
|
||||
*p_is_dir = (fno.fattrib & AM_DIR) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lftpd_io_closedir(void *dp)
|
||||
{
|
||||
if (dp != NULL) {
|
||||
f_closedir((DIR *)dp);
|
||||
free(dp);
|
||||
}
|
||||
}
|
||||
18
Drivers/BSP/NET/lftpd/lftpd_log.c
Normal file
18
Drivers/BSP/NET/lftpd/lftpd_log.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "private/lftpd_log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
void lftpd_log_internal(const char* level, const char* format, ...) {
|
||||
char buffer[256];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int err = vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
if (err >= sizeof(buffer)) {
|
||||
return;
|
||||
}
|
||||
printf("%s %s\n", level, buffer);
|
||||
}
|
||||
16
Drivers/BSP/NET/lftpd/lftpd_string.c
Normal file
16
Drivers/BSP/NET/lftpd/lftpd_string.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "private/lftpd_string.h"
|
||||
|
||||
char *lftpd_string_trim(char *s)
|
||||
{
|
||||
char *p = s;
|
||||
for (int i = 0, len = (int)strlen(s); i < len && isspace((int)s[i]); i++) {
|
||||
p++;
|
||||
}
|
||||
for (int i = (int)strlen(p); i >= 0 && isspace((int)p[i]); i--) {
|
||||
p[i] = '\0';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
14
Drivers/BSP/NET/lftpd/private/lftpd_inet.h
Normal file
14
Drivers/BSP/NET/lftpd/private/lftpd_inet.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int lftpd_inet_listen(int port);
|
||||
int lftpd_inet_listen_multi(int port, int backlog);
|
||||
int lftpd_inet_get_socket_port(int socket);
|
||||
int lftpd_inet_accept(int socket);
|
||||
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len);
|
||||
int lftpd_inet_write_string(int socket, const char *message);
|
||||
int lftpd_inet_write(int socket, const void *buf, int len);
|
||||
int lftpd_inet_read(int socket, void *buf, int len);
|
||||
int lftpd_inet_close(int socket);
|
||||
18
Drivers/BSP/NET/lftpd/private/lftpd_io.h
Normal file
18
Drivers/BSP/NET/lftpd/private/lftpd_io.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
char *lftpd_io_canonicalize_path(const char *base, const char *name);
|
||||
|
||||
int lftpd_io_open_read(const char *path);
|
||||
int lftpd_io_open_write(const char *path);
|
||||
int lftpd_io_read(int handle, void *buf, int len);
|
||||
int lftpd_io_write(int handle, const void *buf, int len);
|
||||
void lftpd_io_close(int handle);
|
||||
|
||||
int lftpd_io_stat(const char *path, uint32_t *p_size, int *p_is_dir);
|
||||
int lftpd_io_unlink(const char *path);
|
||||
|
||||
void *lftpd_io_opendir(const char *path);
|
||||
int lftpd_io_readdir(void *dp, char *name, int name_max, uint32_t *p_size, int *p_is_dir);
|
||||
void lftpd_io_closedir(void *dp);
|
||||
7
Drivers/BSP/NET/lftpd/private/lftpd_log.h
Normal file
7
Drivers/BSP/NET/lftpd/private/lftpd_log.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "dbg_log.h"
|
||||
|
||||
#define lftpd_log_error(format, ...) DBG_ERROR("[FTP] " format, ##__VA_ARGS__)
|
||||
#define lftpd_log_info(format, ...) DBG_INFO("[FTP] " format, ##__VA_ARGS__)
|
||||
#define lftpd_log_debug(format, ...)
|
||||
42
Drivers/BSP/NET/lftpd/private/lftpd_status.h
Normal file
42
Drivers/BSP/NET/lftpd/private/lftpd_status.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#define STATUS_110 "Restart marker reply."
|
||||
#define STATUS_120 "Service ready in %d minutes."
|
||||
#define STATUS_125 "Data connection already open; transfer starting."
|
||||
#define STATUS_150 "File status okay; about to open data connection."
|
||||
#define STATUS_200 "Command okay."
|
||||
#define STATUS_202 "Command not implemented, superfluous at this site."
|
||||
#define STATUS_211 "System status, or system help reply."
|
||||
#define STATUS_212 "Directory status."
|
||||
#define STATUS_213 "File status."
|
||||
#define STATUS_214 "Help message."
|
||||
#define STATUS_215 "%s system type."
|
||||
#define STATUS_220 "Service ready for new user."
|
||||
#define STATUS_221 "Service closing control connection."
|
||||
#define STATUS_225 "Data connection open; no transfer in progress."
|
||||
#define STATUS_226 "Closing data connection."
|
||||
#define STATUS_227 "Entering Passive Mode (%d,%d,%d,%d,%d,%d)."
|
||||
#define STATUS_229 "Entering Extended Passive Mode (|||%d|)."
|
||||
#define STATUS_230 "User logged in, proceed."
|
||||
#define STATUS_250 "Requested file action okay, completed."
|
||||
#define STATUS_257 "\"%s\" created."
|
||||
#define STATUS_331 "User name okay, need password."
|
||||
#define STATUS_332 "Need account for login."
|
||||
#define STATUS_350 "Requested file action pending further information."
|
||||
#define STATUS_421 "Service not available, closing control connection."
|
||||
#define STATUS_425 "Can't open data connection."
|
||||
#define STATUS_426 "Connection closed; transfer aborted."
|
||||
#define STATUS_450 "Requested file action not taken. File unavailable (e.g., file busy)."
|
||||
#define STATUS_451 "Requested action aborted: local error in processing."
|
||||
#define STATUS_452 "Requested action not taken. Insufficient storage space in system."
|
||||
#define STATUS_500 "Syntax error, command unrecognized. This may include errors such as command line too long."
|
||||
#define STATUS_501 "Syntax error in parameters or arguments."
|
||||
#define STATUS_502 "Command not implemented."
|
||||
#define STATUS_503 "Bad sequence of commands."
|
||||
#define STATUS_504 "Command not implemented for that parameter."
|
||||
#define STATUS_530 "Not logged in."
|
||||
#define STATUS_532 "Need account for storing files."
|
||||
#define STATUS_550 "Requested action not taken. File unavailable (e.g., file not found, no access)."
|
||||
#define STATUS_551 "Requested action aborted: page type unknown."
|
||||
#define STATUS_552 "Requested file action aborted. Exceeded storage allocation (for current directory or dataset)."
|
||||
#define STATUS_553 "Requested action not taken. File name not allowed."
|
||||
5
Drivers/BSP/NET/lftpd/private/lftpd_string.h
Normal file
5
Drivers/BSP/NET/lftpd/private/lftpd_string.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define CRLF "\r\n"
|
||||
|
||||
char* lftpd_string_trim(char* s);
|
||||
Reference in New Issue
Block a user