FTP可以上传文件
This commit is contained in:
@@ -182,11 +182,14 @@ static int receive_file(int socket, const char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char buffer[1024];
|
||||
static unsigned char s_recv_buf[4096];
|
||||
int bufsize = 4096;
|
||||
int err;
|
||||
int total = 0;
|
||||
|
||||
while ((err = lftpd_inet_read(socket, buffer, sizeof(buffer))) > 0) {
|
||||
if (lftpd_io_write(fh, buffer, err) != err) {
|
||||
while ((err = lftpd_inet_read(socket, s_recv_buf, bufsize)) > 0) {
|
||||
total += err;
|
||||
if (lftpd_io_write(fh, s_recv_buf, err) != err) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
@@ -197,6 +200,11 @@ static int receive_file(int socket, const char *path)
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
if (total == 0) {
|
||||
lftpd_log_error("received 0 bytes");
|
||||
lftpd_io_unlink(path);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -209,18 +217,15 @@ static int cmd_cwd(lftpd_client_t *client, const char *arg)
|
||||
|
||||
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;
|
||||
/* 根目录始终有效,跳过 stat 检查(FatFS FF_FS_RPATH=0 下 stat 根目录可能失败) */
|
||||
if (strcmp(path, "/") != 0) {
|
||||
uint32_t size;
|
||||
int is_dir;
|
||||
if (lftpd_io_stat(path, &size, &is_dir) != 0 || !is_dir) {
|
||||
send_simple_response(client->socket, 550, STATUS_550);
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(client->directory, path, sizeof(client->directory) - 1);
|
||||
@@ -262,6 +267,11 @@ static int cmd_dele(lftpd_client_t *client, const char *arg)
|
||||
|
||||
static int cmd_epsv(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
if (client->data_socket >= 0) {
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
}
|
||||
|
||||
int listener_socket = lftpd_inet_listen(0);
|
||||
if (listener_socket < 0) {
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
@@ -272,16 +282,9 @@ static int cmd_epsv(lftpd_client_t *client, const char *arg)
|
||||
|
||||
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...");
|
||||
lftpd_log_debug("EPSV listener on port %d", port);
|
||||
|
||||
client->data_socket = data_sock;
|
||||
client->data_socket = listener_socket;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -304,8 +307,17 @@ static int cmd_list(lftpd_client_t *client, const char *arg)
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
int err = send_list(client->data_socket, client->directory);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
|
||||
if (data_sock < 0) {
|
||||
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = send_list(data_sock, client->directory);
|
||||
lftpd_inet_close(data_sock);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
@@ -324,8 +336,17 @@ static int cmd_nlst(lftpd_client_t *client, const char *arg)
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
int err = send_nlst(client->data_socket, client->directory);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
|
||||
if (data_sock < 0) {
|
||||
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = send_nlst(data_sock, client->directory);
|
||||
lftpd_inet_close(data_sock);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
@@ -353,6 +374,11 @@ static int cmd_pasv(lftpd_client_t *client, const char *arg)
|
||||
int listener_socket = -1;
|
||||
int retry;
|
||||
|
||||
if (client->data_socket >= 0) {
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
}
|
||||
|
||||
for (retry = 0; retry < 3; retry++) {
|
||||
listener_socket = lftpd_inet_listen(0);
|
||||
if (listener_socket >= 0) break;
|
||||
@@ -386,16 +412,9 @@ static int cmd_pasv(lftpd_client_t *client, const char *arg)
|
||||
(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...");
|
||||
lftpd_log_debug("PASV listener on port %d", port);
|
||||
|
||||
client->data_socket = data_sock;
|
||||
client->data_socket = listener_socket;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -419,18 +438,29 @@ static int cmd_retr(lftpd_client_t *client, const char *arg)
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
|
||||
if (data_sock < 0) {
|
||||
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
int err = send_file(data_sock, path);
|
||||
lftpd_inet_close(data_sock);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
lftpd_log_info("DOWNLOAD '%s' OK", path);
|
||||
send_simple_response(client->socket, 226, STATUS_226);
|
||||
} else {
|
||||
lftpd_log_error("DOWNLOAD '%s' FAILED", path);
|
||||
send_simple_response(client->socket, 450, STATUS_450);
|
||||
}
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -464,18 +494,32 @@ static int cmd_stor(lftpd_client_t *client, const char *arg)
|
||||
}
|
||||
|
||||
send_simple_response(client->socket, 150, STATUS_150);
|
||||
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
|
||||
if (data_sock < 0) {
|
||||
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
|
||||
send_simple_response(client->socket, 425, STATUS_425);
|
||||
lftpd_inet_close(client->data_socket);
|
||||
client->data_socket = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
int err = receive_file(data_sock, path);
|
||||
lftpd_inet_close(data_sock);
|
||||
client->data_socket = -1;
|
||||
|
||||
if (err == 0) {
|
||||
uint32_t size = 0;
|
||||
int is_dir = 0;
|
||||
lftpd_io_stat(path, &size, &is_dir);
|
||||
lftpd_log_info("UPLOAD '%s' %lu bytes OK", path, (unsigned long)size);
|
||||
send_simple_response(client->socket, 226, STATUS_226);
|
||||
} else {
|
||||
lftpd_log_error("UPLOAD '%s' FAILED", path);
|
||||
send_simple_response(client->socket, 450, STATUS_450);
|
||||
}
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -548,6 +592,7 @@ static int handle_control_channel(lftpd_client_t *client)
|
||||
arg = lftpd_string_trim(arg_buf);
|
||||
}
|
||||
|
||||
lftpd_log_info("CMD %s %s", command_tmp, arg ? arg : "");
|
||||
err = commands[i].handler(client, arg);
|
||||
matched = true;
|
||||
break;
|
||||
@@ -585,7 +630,7 @@ int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
|
||||
if (client_socket < 0) {
|
||||
lftpd_log_error("error accepting client socket");
|
||||
lftpd_inet_close(lftpd->server_socket);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -614,14 +659,9 @@ int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
|
||||
handle_control_channel(&client);
|
||||
lftpd->client = NULL;
|
||||
|
||||
/* 等待 CH395F 稳定(Trap 09) */
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
|
||||
/* standalone mode: socket was closed in handle_control_channel,
|
||||
* loop back to create a new listener */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lftpd_stop(lftpd_t *lftpd)
|
||||
|
||||
@@ -7,30 +7,40 @@
|
||||
|
||||
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;
|
||||
}
|
||||
int retry;
|
||||
int s;
|
||||
|
||||
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;
|
||||
for (retry = 0; retry < 5; retry++) {
|
||||
s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
if (retry == 0) DBG_ERROR("create socket");
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
continue;
|
||||
}
|
||||
|
||||
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("bind port %d", port);
|
||||
net_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (net_listen(s, 0) >= 0) {
|
||||
return s;
|
||||
}
|
||||
|
||||
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 (retry < 4) {
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
}
|
||||
}
|
||||
|
||||
if (net_listen(s, 0) < 0) {
|
||||
DBG_ERROR("error listening on socket");
|
||||
net_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
DBG_ERROR("listen failed after 5 retries (total 10s wait)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lftpd_inet_listen_multi(int port, int backlog)
|
||||
@@ -81,10 +91,33 @@ int lftpd_inet_accept(int socket)
|
||||
if (s >= 0) {
|
||||
return s;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
|
||||
int lftpd_inet_accept_timeout(int socket, int timeout_ms)
|
||||
{
|
||||
int elapsed = 0;
|
||||
|
||||
while (elapsed < timeout_ms) {
|
||||
int s = net_accept(socket, NULL, NULL);
|
||||
if (s >= 0) {
|
||||
return s;
|
||||
}
|
||||
/* 数据连接已被对端关闭时提前退出,不等待超时 */
|
||||
net_sock_t *p_sock = net_get_sock(socket);
|
||||
if (p_sock == NULL || p_sock->state != NET_SOCK_STATE_LISTENING) {
|
||||
DBG_ERROR("data socket closed, accept aborted");
|
||||
return -1;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
elapsed += 100;
|
||||
}
|
||||
|
||||
DBG_ERROR("accept timeout (%dms)", timeout_ms);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len)
|
||||
{
|
||||
memset(buffer, 0, buffer_len);
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
|
||||
/*
|
||||
* FatFS 在 FF_USE_LFN=0 时不接受 "/" 前缀路径。
|
||||
* 剥离前导 "/" 后用 FatFS 兼容路径,根目录用 "." 替代空字符串。
|
||||
* 剥离前导 "/" 后用 FatFS 兼容路径,根目录用 "0:"(驱动号格式)替代。
|
||||
*/
|
||||
static const char *to_fatfs_path(const char *path)
|
||||
{
|
||||
if (path == NULL || *path == '\0') {
|
||||
return ".";
|
||||
return "0:";
|
||||
}
|
||||
if (*path == '/') {
|
||||
path++;
|
||||
if (*path == '\0') {
|
||||
return ".";
|
||||
return "0:";
|
||||
}
|
||||
}
|
||||
return path;
|
||||
|
||||
@@ -7,6 +7,7 @@ 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_accept_timeout(int socket, int timeout_ms);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user