diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-06-01 19:15:14 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-06-01 19:15:14 +0000 |
commit | c505c3eb243de07b8a59d71b5dbe5683ee9466f4 (patch) | |
tree | 67da5ab592d26f8901fe47da44d5f21967277d1b /apps/netutils/ftpc | |
parent | 7130c3c2de1b2e7647584b400367fbaae75d93a4 (diff) | |
download | nuttx-c505c3eb243de07b8a59d71b5dbe5683ee9466f4.tar.gz nuttx-c505c3eb243de07b8a59d71b5dbe5683ee9466f4.tar.bz2 nuttx-c505c3eb243de07b8a59d71b5dbe5683ee9466f4.zip |
First cut at FTP client
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3654 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'apps/netutils/ftpc')
29 files changed, 5242 insertions, 0 deletions
diff --git a/apps/netutils/ftpc/Makefile b/apps/netutils/ftpc/Makefile new file mode 100644 index 000000000..9c5862a53 --- /dev/null +++ b/apps/netutils/ftpc/Makefile @@ -0,0 +1,113 @@ +############################################################################ +# apps/netutils/ftpc/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# DHCP Daemn Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +# FTP connection management +CSRCS = ftpc_connect.c ftpc_disconnect.c + +# FTP commands +CSRCS += ftpc_cdup.c ftpc_chdir.c ftpc_chmod.c ftpc_filesize.c ftpc_filetime.c +CSRCS += ftpc_help.c ftpc_idle.c ftpc_listdir.c ftpc_login.c ftpc_mkdir.c +CSRCS += ftpc_noop.c ftpc_pwd.c ftpc_quit.c ftpc_rename.c ftpc_rmdir.c ftpc_unlink.c +CSRCS += ftpc_cmd.c + +# FTP transfers +CSRCS += ftpc_getfile.c ftpc_putfile.c ftpc_transfer.c + +# FTP responses +CSRCS += ftpc_response.c ftpc_getreply.c + +# FTP helpers +CSRCS += ftpc_utils.c ftpc_socket.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/ftpc/README.txt b/apps/netutils/ftpc/README.txt new file mode 100644 index 000000000..d995227c7 --- /dev/null +++ b/apps/netutils/ftpc/README.txt @@ -0,0 +1,81 @@ +/* FTP Commands *************************************************************/ +/* Command summary: + * + * ABOR - abort a file transfer + * ACCT - send account information + * APPE - append to a remote file + * CDUP - CWD to the parent of the current directory + * CWD - change working directory + * DELE - delete a remote file + * HELP - return help on using the server + * LIST - list remote files + * MDTM - return the modification time of a file + * MKD - make a remote directory + * MLSD - Standardized directory listing (instead of LIST) + * MLST - Standardized object listing (instead of LIST) + * MODE - set transfer mode + * NLST - name list of remote directory + * NOOP - do nothing + * PASS - send password + * PASV - enter passive mode + * PORT - open a data port + * PWD - print working directory + * QUIT - terminate the connection + * REIN - reinitialize the connection + * RETR - retrieve a remote file + * REST - Sets the point at which a file transfer should start + * RMD - remove a remote directory + * RNFR - rename from + * RNTO - rename to + * SITE - site-specific commands + * SIZE - return the size of a file + * STOR - store a file on the remote host + * STOU - store a file uniquely + * STRU - set file transfer structure + * STAT - return server status + * SYST - return system type + * TYPE - set transfer type + * USER - send username + * +/* FTP Replies **************************************************************/ + * + * 110 - Restart marker reply. + * 120 - Service ready in nnn minutes. + * 125 - Data connection already open; transfer starting. + * 150 - File status okay; about to open data connection. + * 200 - Command okay. + * 202 - Command not implemented, superfluous at this site. + * 211 - System status, or system help reply. + * 212 - Directory status. + * 213 - File status. + * 214 - Help message. + * 215 - NAME system type. + * 220 - Service ready for new user. + * 221 - Service closing control connection. + * 225 - Data connection open; no transfer in progress. + * 226 - Closing data connection. + * 227 - Entering Passive Mode (h1,h2,h3,h4,p1,p2). + * 230 - User logged in, proceed. + * 250 - Requested file action okay, completed. + * 257 - "PATHNAME" created. + * 331 - User name okay, need password. + * 332 - Need account for login. + * 350 - Requested file action pending further information. + * 421 - Service not available, closing control connection. + * 425 - Can't open data connection. + * 426 - Connection closed; transfer aborted. + * 450 - Requested file action not taken. + * 451 - Requested action aborted: local error in processing. + * 452 - Requested action not taken. + * 500 - Syntax error, command unrecognized. + * 501 - Syntax error in parameters or arguments. + * 502 - Command not implemented. + * 503 - Bad sequence of commands. + * 504 - Command not implemented for that parameter. + * 530 - Not logged in. + * 532 - Need account for storing files. + * 550 - Requested action not taken. + * 551 - Requested action aborted: page type unknown. + * 552 - Requested file action aborted. + * 553 - Requested action not taken. + */ diff --git a/apps/netutils/ftpc/ftpc_cdup.c b/apps/netutils/ftpc/ftpc_cdup.c new file mode 100644 index 000000000..323033390 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_cdup.c @@ -0,0 +1,87 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_cdup.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_cdup + * + * Description: + * Make the parent of the current directory be the new current directory. + * + ****************************************************************************/ + + int ftpc_cdup(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + ret = ftpc_cmd(session, "CDUP"); + ftpc_curdir(session); + return ret; +} + diff --git a/apps/netutils/ftpc/ftpc_chdir.c b/apps/netutils/ftpc/ftpc_chdir.c new file mode 100644 index 000000000..ddf6452c4 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_chdir.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_chdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_chdir + * + * Description: + * Change the current working directory. + * + ****************************************************************************/ + +int ftpc_chdir(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + ret = ftpc_cmd(session, "CWD %s", path); + if (ret != OK) + { + return ret; + } + + ftpc_curdir(session); + return OK; +} diff --git a/apps/netutils/ftpc/ftpc_chmod.c b/apps/netutils/ftpc/ftpc_chmod.c new file mode 100644 index 000000000..332df2b0c --- /dev/null +++ b/apps/netutils/ftpc/ftpc_chmod.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_chmod.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <debug.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_chmod + * + * Description: + * Change the protections on the remote file. + * + ****************************************************************************/ + +int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + /* Does the server support the size CHMOD command? */ + + if (FTPC_HAS_CHMOD(session)) + { + ret = ftpc_cmd(session, "SITE CHMOD %s %s", mode, path); + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* No.. the server does not support the SITE CHMOD command */ + + FTPC_CLR_CHMOD(session); + } + + return OK; + } + else + { + ndbg("Server does not support SITE CHMOD\n"); + } + + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_cmd.c b/apps/netutils/ftpc/ftpc_cmd.c new file mode 100644 index 000000000..240a513e8 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_cmd.c @@ -0,0 +1,237 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_cmd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <stdarg.h> +#include <debug.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_restore + * + * Description: + * Restore the connection to the server and log in again. + * + ****************************************************************************/ + +#ifdef CONFIG_FTP_AUTORECONNECT +static int ftpc_restore(struct ftpc_session_s *session) +{ + int ret; + + if (session) + { + /* Set the initial directory to the last valid current directory */ + + free(session->initdir); + session->initdir = ftpc_dequote(session->curdir); + + /* Reconnect to the server */ + + ret = ftpc_reconnect(session); + if (ret == 0) + { + /* Log into the server */ + + ret = ftpc_relogin(session); + } + else + { + /* Failed to reconnect to the server */ + + ftpc_reset(session); + } + return ret; + } + + return ERROR; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_cmd + * + * Description: + * Send the specified command to the server. + * + ****************************************************************************/ + +int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...) +{ + va_list ap; +#ifdef CONFIG_FTP_AUTORECONNECT + bool reconnect = false; +#endif + int ret; + + /* Verify that we are still connecte to the server */ + + if (!ftpc_sockconnected(&session->cmd)) + { + ndbg("Cmd channel si not connected\n"); + goto errout; + } + + /* Loop, reconnecting as necessary until the command is sent */ + +#ifdef CONFIG_FTP_AUTORECONNECT + for (;;) +#endif + { + /* Send the command */ + + va_start(ap, cmd); + ret = ftpc_sockprintf(&session->cmd, cmd, ap); + if (ret >= 0) + { + ret = ftpc_sockprintf(&session->cmd, "\r\n"); + if (ret >= 0) + { + ret = ftpc_sockflush(&session->cmd); + } + } + va_end(ap); + + /* Check for an error in sending the data */ + + if (ret < 0) + { + ndbg("Error sending cmd: %s, %d\n" cmd, errno); + goto errout; + } + + /* Get the response to the command */ + + ret = fptc_getreply(session); + if (ret < 0) + { + ndbg("Error getting reply: %d\n" errno); + goto errout; + } + + /* Check for "421 Service not available, closing control connection" */ + + if (session->code == 421) + { + /* Server is closing the control connection. */ + + ndbg("Server closed control connection\n"); + + /* If we were previously logged in and this is not a QUIT commnad + * then attempt to automatically reconnect to the server. + */ + +#ifdef CONFIG_FTP_AUTORECONNECT + if (ftpc_loggedin(session) && strcasecmp(cmd, "QUIT") != 0) + { + /* Don't try re-connecting more than once */ + + if (reconnect) + { + ndbg("Reconnect failed\n"); + goto errout; + } + else + { + /* Try to restore the connection and, if successful, + * continue the loop and try to send the command again. + */ + + ndbg("Reconnecting...\n"); + reconnect = true; + ret = ftpc_restore(); + if (ret < 0) + { + ndbg("Failed to restore the connection"); + goto errout; + } + continue; + } + } + else +#endif + { + /* Don't try to connect, just return an error (retaining + * the session response code (421) + */ + + return ERROR; + } + } + + /* The command was successfully sent */ + + return OK; + } + +errout: + session->code = -1; + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_connect.c b/apps/netutils/ftpc/ftpc_connect.c new file mode 100644 index 000000000..94add3d54 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_connect.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_connect.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <errno.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_connect + * + * Description: + * Create a session handle and connect to the server. + * + ****************************************************************************/ + +SESSION ftpc_connect(FAR struct ftpc_connect_s *server) +{ + FAR struct ftpc_session_s *session; + int ret; + + /* Allocate a session structure */ + + session = (struct ftpc_session_s *)zalloc(sizeof(struct ftpc_session_s)); + if (!session) + { + ndbg("Failed to allocate a session\n"); + set_errno(ENOMEM); + goto errout; + } + + /* Initialize the session structure */ + + session->addr.s_addr = server->addr.s_addr; + session->port = server->port; + + /* Create up a timer to prevent hangs */ + + session->wdog = wd_create(); + + /* And (Re-)connect to the server */ + + ret = ftpc_reconnect(session); + if (ret != OK) + { + ndbg("ftpc_reconnect() failed: %d\n", errno); + goto errout_with_alloc; + } + return (SESSION)session; + +errout_with_alloc: + free(session); +errout: + return NULL; +} + +/**************************************************************************** + * Name: ftpc_reconnect + * + * Description: + * re-connect to the server either initially, or after loss of connection. + * + ****************************************************************************/ + +int ftpc_reconnect(FAR struct ftpc_session_s *session) +{ + struct sockaddr_in addr; +#ifdef CONFIG_DEBUG + char *tmp; +#endif + int ret; + + /* Re-initialize the session structure */ + + session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->xfrmode = FTPC_XFRMODE_UNKNOWN; + + /* Set up a timer to prevent hangs */ + + ret = wd_start(session->wdog, session->conntimeo, ftpc_conntimeo, 1, session); + if (ret != OK) + { + ndbg("wd_start() failed\n"); + goto errout; + } + + /* Initialize a socket */ + + ret = ftpc_sockinit(&session->cmd); + if (ret != OK) + { + ndbg("ftpc_sockinit() failed: %d\n", errno); + goto errout; + } + + /* Connect the socket to the server */ + +#ifdef CONFIG_DEBUG + tmp = inet_ntoa(session->addr); + ndbg("Connecting to server address %s:%d\n", + server->proxy ? "proxy" : "server", tmp, ntohl(session->port)); + free(tmp); +#endif + + addr.sin_family = AF_INET; + addr.sin_port = session->port; + addr.sin_addr.s_addr = session->addr.s_addr; + ret = ftpc_sockconnect(&session->cmd, &addr); + if (ret != OK) + { + ndbg("ftpc_sockconnect() failed: %d\n", errno); + goto errout_with_socket; + } + + /* Read startup message from server */ + + fptc_getreply(session); + + /* Check for "120 Service ready in nnn minutes" */ + + if (session->code == 120) + { + fptc_getreply(session); + } + wd_cancel(session->wdog); + + if (!ftpc_sockconnected(&session->cmd)) + { + ftpc_reset(session); + goto errout; + } + + /* Check for "220 Service ready for new user" */ + + if (session->code == 220) + { + FTPC_SET_CONNECTED(session); + } + + if (!FTPC_IS_CONNECTED(session)) + { + goto errout_with_socket; + } + +#ifdef CONFIG_DEBUG + ndbg("Connected\n"); + tmp = inet_ntoa(session->cmd.raddr.sin_addr.s_addr); + ndbg(" Remote address: %s:%d\n", tmp, ntohl(session->cmd.raddr.sin_port)); + free(tmp); + tmp = inet_ntoa(session->cmd.laddr.sin_addr.s_addr); + ndbg(" Local address: %s:d\n", tmp, ntohl(session->cmd.laddr.sin_port)); + free(tmp); +#endif + return OK; + +errout_with_socket: + ftpc_sockclose(&session->cmd); +errout: + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_disconnect.c b/apps/netutils/ftpc/ftpc_disconnect.c new file mode 100644 index 000000000..e55c35e34 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_disconnect.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_disconnect.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_disconnect + * + * Description: + * Disconnect from the server and destroy the session handle.. + * + ****************************************************************************/ + +void ftpc_disconnect(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + if (session) + { + /* Release sockets */ + + ftpc_sockclose(&session->data); + ftpc_sockclose(&session->cmd); + + /* Free strings */ + + free(session->uname); + free(session->pwd); + free(session->initdir); + free(session->homedir); + free(session->curdir); + free(session->prevdir); + free(session->rname); + free(session->lname); + + /* Then destroy the session */ + + free(session); + } +} diff --git a/apps/netutils/ftpc/ftpc_filesize.c b/apps/netutils/ftpc/ftpc_filesize.c new file mode 100644 index 000000000..afd773e41 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_filesize.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_filesize.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_filesize + * + * Description: + * Return the size of the given file on the remote server. + * + ****************************************************************************/ + + uint64_t ftpc_filesize(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + uint64_t ret; + + /* Check if the host supports the SIZE command */ + + if (!FTPC_HAS_SIZE(session)) + { + return ERROR; + } + + if (ftpc_xfrmode(session, FTPC_XFRMODE_ASCII) != 0) + { + return ERROR; + } + + ret = ftpc_cmd(session, "SIZE %s", path); + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* No.. the host does not support the SIZE command */ + + FTPC_CLR_SIZE(session); + return ERROR; + } + + sscanf(session->reply, "%*s %llu", &ret); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_filetime.c b/apps/netutils/ftpc/ftpc_filetime.c new file mode 100644 index 000000000..331e7e7b6 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_filetime.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_filetime.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <time.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_filetime + * + * Descripton: + * Return the timestamp on the remote file. + * + ****************************************************************************/ + +time_t ftpc_filetime(SESSION handle, FAR const char *filename) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct tm timestamp; + int ret; + + /* Make sure that the server is still connected */ + + if (!ftpc_connected(session)) + { + return ERROR; + } + + /* Does the server support the MDTM command? */ + + if (!FTPC_HAS_MDTM(session)) + { + return ERROR; + } + + /* Get the file time in UTC */ + + memset(×tamp, 0, sizeof(timestamp)); + ret = ftpc_cmd(session, "MDTM %s", filename); + if (ret != OK) + { + return ERROR; + } + + /* Check for "202 Command not implemented, superfluous at this site" */ + + if (session->code == 202) + { + FTPC_CLR_MDTM(session); + return ERROR; + } + + /* Check for "213 File status" */ + + if (session->code != 213) + { + return ERROR; + } + + /* Time is Universal Coordinated Time */ + + sscanf(session->reply, "%*s %04d%02d%02d%02d%02d%02d", + ×tamp.tm_year, ×tamp.tm_mon, ×tamp.tm_mday, + ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec); + timestamp.tm_year -= 1900; + timestamp.tm_mon--; + return mktime(×tamp); +} diff --git a/apps/netutils/ftpc/ftpc_getfile.c b/apps/netutils/ftpc/ftpc_getfile.c new file mode 100644 index 000000000..a3ea5008d --- /dev/null +++ b/apps/netutils/ftpc/ftpc_getfile.c @@ -0,0 +1,398 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_getfile.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <debug.h> +#include <errno.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_recvinit + * + * Description: + * Initialize to receive a file + * + ****************************************************************************/ + +static int ftpc_recvinit(struct ftpc_session_s *session, FAR const char *path, + uint8_t xfrmode, off_t offset) +{ + int ret; + + /* Reset transfer related variables */ + + ftpc_xfrreset(session); + + ret = ftpc_xfrinit(session); + if (ret != OK) + { + return ERROR; + } + + /* Configure the transfer: Initial file offset and tranfer mode */ + + session->offset = 0; + session->filesize = -1; + ftpc_xfrmode(session, xfrmode); + + /* Handle the resume offset (caller is responsible for fseeking in the + * file) + */ + + if (offset > 0) + { + /* Send the REST command. This command sets the offset where the + * transfer should start. This must come after PORT or PASV commands. + */ + + ret = ftpc_cmd(session, "REST %ld", offset); + if (ret < 0) + { + ndbg("REST command failed: %d\n", errno); + return ERROR; + } + + session->size = offset; + session->rstrsize = offset; + } + + /* Send the RETR (Retrieve a remote file) command */ + + ret = ftpc_cmd(session, "RETR %s", path); + if (ret < 0) + { + ndbg("RETR command failed: %d\n", errno); + return ERROR; + } + + /* Accept a connection on the data socket */ + + ret = ftpc_sockaccept(&session->data, "r", FTPC_IS_PASSIVE(session)); + if (ret != OK) + { + ndbg("data connection not accepted\n"); + } + + return ret; +} + +/**************************************************************************** + * Name: ftpc_waitinput + * + * Description: + * Wait to receive data. + * + ****************************************************************************/ + +static int ftpc_waitinput(FAR struct ftpc_session_s *session) +{ + int ret; + do { + ret = ftpc_waitdata(session, session->data.instream, true); + if (ret == -1) { + if (errno == EINTR) + { + FTPC_SET_INTERRUPT(session); + } + return ERROR; + } + } while(ret == 0); + + return OK; +} + +/**************************************************************************** + * Name: ftpc_recvbinary + * + * Description: + * Receive a binary file. + * + ****************************************************************************/ + +static int ftpc_recvbinary(FAR struct ftpc_session_s *session, + FAR FILE *rinstream, FAR FILE *loutstream) +{ + FAR char *buf; + ssize_t nread; + ssize_t nwritten; + int err; + int ret = OK; + + buf = (FAR char *)malloc(CONFIG_FTP_BUFSIZE); + if (!buf) + { + err = ENOMEM; + goto errout_with_err; + } + + while (!feof(rinstream)) + { + if (ftpc_waitinput(session) != 0) + { + nvdbg("ftpc_waitinput() failed\n"); + err = EIO; + goto errout_with_buf; + } + + nread = fread(buf, sizeof(char), CONFIG_FTP_BUFSIZE, rinstream); + if (nread <= 0) + { + (void)ftpc_xfrabort(session, rinstream); + ret = ERROR; + break; + } + + nwritten = fwrite(buf, sizeof(char), nread, loutstream); + if (nwritten != nread) + { + (void)ftpc_xfrabort(session, loutstream); + ret = ERROR; + break; + } + + session->size += nread; + } + + free(buf); + return ret; + +errout_with_buf: + free(buf); +errout_with_err: + set_errno(err); + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_getfile + * + * Description: + * Get a file from the remote host. + * + ****************************************************************************/ + +int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname, + uint8_t how, uint8_t xfrmode) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct stat statbuf; + FILE *loutstream; + off_t offset; + int ret; + + /* Get information about the local file */ + + ret = stat(lname, &statbuf); + if (ret == 0) + { + /* It already exists. Is it a directory? */ + + if (S_ISDIR(statbuf.st_mode)) + { + ndbg("'%s' is a directory\n", lname); + return ERROR; + } + } + + /* Is it write-able? */ + +#ifdef S_IWRITE + if (!(statbuf.st_mode & S_IWRITE)) + { + ndbg("'%s' permission denied\n", lname); + return ERROR; + } +#endif + + /* Are we resuming the transfers? Is so then the starting offset is the + * size of the existing, partial file. + */ + + if (how == FTPC_GET_RESUME) + { + offset = statbuf.st_size; + } + else + { + offset = 0; + } + + /* Setup to receive the file */ + + ret = ftpc_recvinit(session, rname, xfrmode, offset); + if (ret != OK) + { + ndbg("ftpc_recvinit failed\n"); + return ERROR; + } + + loutstream = fopen(lname, (offset > 0 || (how == FTPC_GET_APPEND)) ? "a" : "w"); + if (!loutstream) + { + ndbg("fopen failed: %d\n", errno); + session->offset = 0; + return ERROR; + } + + if (offset > 0) + { + ret = fseek(loutstream, offset, SEEK_SET); + if (ret != OK) + { + ndbg("fseek failed: %d\n", errno); + fclose(loutstream); + session->offset = 0; + return ERROR; + } + } + + /* Save the new local and remote file names */ + + free(session->rname); + free(session->lname); + session->rname = strdup(rname); + session->lname = strdup(lname); + + /* And receive the new file data */ + + if (xfrmode == FTPC_XFRMODE_ASCII) + { + ret = ftpc_recvbinary(session, session->data.instream, loutstream); + } + else + { + ret = ftpc_recvtext(session, session->data.instream, loutstream); + } + + ftpc_sockclose(&session->data); + + if (ret == 0) + { + fptc_getreply(session); + } + + fclose(loutstream); + return (ret == OK && !FTPC_INTERRUPTED(session)) ? OK : ERROR; +} + +/**************************************************************************** + * Name: ftpc_recvbinary + * + * Description: + * Receive a text file. + * + ****************************************************************************/ + +int ftpc_recvtext(FAR struct ftpc_session_s *session, + FAR FILE *rinstream, FAR FILE *loutstream) +{ + char *buf = (char *)malloc(CONFIG_FTP_BUFSIZE); + int c; + int ret = OK; + + while((c = fgetc(rinstream)) != EOF) { + + if (ftpc_waitinput(session) != 0) + { + break; + } + + if (c == '\r') + { + c = fgetc(rinstream); + if (c == EOF) + { + (void)ftpc_xfrabort(session, rinstream); + ret = ERROR; + break; + } + if (c != '\n') + { + ungetc(c, rinstream); + c = '\r'; + } + } + + if (fputc(c, loutstream) == EOF) + { + (void)ftpc_xfrabort(session, loutstream); + ret = ERROR; + break; + } + + session->size++; + } + + free(buf); + return ret; +} + + diff --git a/apps/netutils/ftpc/ftpc_getreply.c b/apps/netutils/ftpc/ftpc_getreply.c new file mode 100644 index 000000000..86f1c7bfa --- /dev/null +++ b/apps/netutils/ftpc/ftpc_getreply.c @@ -0,0 +1,241 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_getreply.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <string.h> +#include <debug.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_gets + ****************************************************************************/ + +static int ftpc_gets(struct ftpc_session_s *session) +{ + int ch; + int i = 0; + + /* Start wth an empty response string */ + + session->reply[0] = '\0'; + + /* Verify that the command channel is still connected */ + + if (!ftpc_sockconnected(&session->cmd)) + { + ndbg("Cmd channel disconnected\n"); + return ERROR; + } + + /* Loop until the full line is obtained */ + + for (;;) + { + /* Get the next character from incoming command stream */ + + ch = ftpc_sockgetc(&session->cmd); + if (ch == EOF) + { + ndbg("EOF: Server closed command stream\n"); + ftpc_reset(session); + return ERROR; + } + else if (ch == TELNET_IAC) + { + /* Handle TELNET commands */ + + switch(ch = ftpc_sockgetc(&session->cmd)) + { + case TELNET_WILL: + case TELNET_WONT: + ch = ftpc_sockgetc(&session->cmd); + ftpc_sockprintf(&session->cmd, "%c%c%c", TELNET_IAC, TELNET_DONT, ch); + ftpc_sockflush(&session->cmd); + break; + + case TELNET_DO: + case TELNET_DONT: + ch = ftpc_sockgetc(&session->cmd); + ftpc_sockprintf(&session->cmd, "%c%c%c", TELNET_IAC, TELNET_WONT, ch); + ftpc_sockflush(&session->cmd); + break; + + default: + break; + } + + continue; + } + else if (ch == ISO_cr) + { + ch = ftpc_sockgetc(&session->cmd); + if (ch == '\0') + { + ch = ISO_cr; + } + else if (ch == ISO_nl) + { + session->reply[i++] = (char)ch; + break; + } + else if (ch != EOF) + { + /* TELNET protocol */ + + ungetc(ch, session->cmd.instream); + continue; + } + } + else if (ch == ISO_nl) + { + /* The ISO newline character terminates the string. Just break + * out of the loop. + */ + + break; + } + + if (i < CONFIG_FTP_MAXREPLY) + { + session->reply[i++] = (char)ch; + } + + if (i >= CONFIG_FTP_MAXREPLY) + { + ndbg("Reply truncated\n"); + i = CONFIG_FTP_MAXREPLY; + } + } + + session->reply[i] = '\0'; + session->code = atoi(session->reply); + ftpc_stripcrlf(session->reply); + return session->code; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_getreply + ****************************************************************************/ + +int fptc_getreply(struct ftpc_session_s *session) +{ + char tmp[5]="xxx "; + int ret; + + /* Set up a timeout */ + + if (session->replytimeo) + { + ret = wd_start(session->wdog, session->replytimeo, ftpc_replytimeo, 1, session); + } + + /* Get the next line from the server */ + + ret = ftpc_gets(session); + + /* Do we still have a connection? */ + + if (!ftpc_sockconnected(&session->cmd)) + { + /* No.. cancel the timer and return an error */ + + wd_cancel(session->wdog); + nvdbg("Lost connection\n"); + return ERROR; + } + + /* Did an error occur? */ + + if (ret < 0) + { + /* No.. cancel the timer and return an error */ + + wd_cancel(session->wdog); + nvdbg("ftpc_gets failed\n"); + return ERROR; + } + + nvdbg("Reply: %s\n", session->reply); + + if (session->reply[3] == '-') + { + /* Multi-line response */ + + strncpy(tmp, session->reply, 3); + do + { + if (ftpc_gets(session) == -1) + { + break; + } + + nvdbg("Reply: %s\n", session->reply); + } while(strncmp(tmp, session->reply, 4) != 0); + } + + wd_cancel(session->wdog); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_help.c b/apps/netutils/ftpc/ftpc_help.c new file mode 100644 index 000000000..2501ca365 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_help.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_help.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_help + * + * Description: + * Request a list of available help commands. This implementation is + * fragementary and no ready for any real use at this time. + * + ****************************************************************************/ + +int ftpc_help(SESSION handle, FAR const char *arg) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + /* Send the HELP command with or without an argument */ + + if (arg) + { + ret = ftpc_cmd(session, "HELP %s", arg); + } + else + { + ret = ftpc_cmd(session, "HELP"); + } + + /* Logic is missing here to return the help string to the caller */ + + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_idle.c b/apps/netutils/ftpc/ftpc_idle.c new file mode 100644 index 000000000..945ca8577 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_idle.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_idle.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <debug.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_idle + * + * Description: + * This command will change the FTP server's idle time limit with the site + * idle ftp command. This is useful if the default time limit is too short + * for the transmission of files). + * + ****************************************************************************/ + +int ftpc_idle(SESSION handle, unsigned int idletime) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret = OK; + + /* Check if the server supports the SITE IDLE command */ + + if (!FTPC_HAS_IDLE(session)) + { + ndbg("Server doesn't support SITE IDLE\n"); + return ERROR; + } + + /* Did the caller provide an IDLE time? Or is this just a query for the + * current IDLE time setting? + */ + + if (idletime) + { + ret = ftpc_cmd(session, "SITE IDLE %u", idletime); + } + else + { + ret = ftpc_cmd(session, "SITE IDLE"); + } + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* Server does not support SITE IDLE */ + + FTPC_CLR_IDLE(session); + } + + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_internal.h b/apps/netutils/ftpc/ftpc_internal.h new file mode 100644 index 000000000..4982e1f20 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_internal.h @@ -0,0 +1,263 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_internal.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H +#define __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <time.h> +#include <wdog.h> + +#include <apps/ftpc.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* MISC definitions *********************************************************/ + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +/* Telnet-related definitions */ + +#define TELNET_DM 242 +#define TELNET_IP 244 +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 + +/* Session flag bits ********************************************************/ + +#define FTPC_FLAG_CONNECTED (1 << 0) /* Connected to host */ +#define FTPC_FLAG_LOGGEDIN (1 << 1) /* Logged in to host */ +#define FTPC_STATE_FLAGS (0x0003) /* State of connection */ + +#define FTPC_FLAG_MDTM (1 << 2) /* Host supports MDTM command */ +#define FTPC_FLAG_SIZE (1 << 3) /* Host supports SIZE command */ +#define FTPC_FLAG_PASV (1 << 4) /* Host supports PASV command */ +#define FTPC_FLAG_STOU (1 << 5) /* Host supports STOU command */ +#define FTPC_FLAG_CHMOD (1 << 6) /* Host supports SITE CHMOD command */ +#define FTPC_FLAG_IDLE (1 << 7) /* Host supports SITE IDLE command */ +#define FTPC_HOSTCAP_FLAGS (0x00fc) /* Host capabilities */ + +#define FTPC_FLAG_INTERRUPT (1 << 8) /* Transfer interrupted */ +#define FTPC_FLAG_PUT (1 << 9) /* Transfer is a PUT operation (upload) */ +#define FTPC_FLAG_PASSIVE (1 << 10) /* Passive mode requested */ +#define FTPC_XFER_FLAGS (0x0700) /* Transfer related */ + +#define FTPC_FLAGS_INIT FTPC_HOSTCAP_FLAGS + +#define FTPC_SET_CONNECTED(s) do { (s)->flags |= FTPC_FLAG_CONNECTED; } while (0) +#define FTPC_SET_LOGGEDIN(s) do { (s)->flags |= FTPC_FLAG_LOGGEDIN; } while (0) +#define FTPC_SET_MDTM(s) do { (s)->flags |= FTPC_FLAG_MDTM; } while (0) +#define FTPC_SET_SIZE(s) do { (s)->flags |= FTPC_FLAG_SIZE; } while (0) +#define FTPC_SET_PASV(s) do { (s)->flags |= FTPC_FLAG_PASV; } while (0) +#define FTPC_SET_STOU(s) do { (s)->flags |= FTPC_FLAG_STOU; } while (0) +#define FTPC_SET_CHMOD(s) do { (s)->flags |= FTPC_FLAG_CHMOD; } while (0) +#define FTPC_SET_IDLE(s) do { (s)->flags |= FTPC_FLAG_IDLE; } while (0) +#define FTPC_SET_INTERRUPT(s) do { (s)->flags |= FTPC_FLAG_INTERRUPT; } while (0) +#define FTPC_SET_PUT(s) do { (s)->flags |= FTPC_FLAG_PUT; } while (0) +#define FTPC_SET_PASSIVE(s) do { (s)->flags |= FTPC_FLAG_PASSIVE; } while (0) + +#define FTPC_CLR_CONNECTED(s) do { (s)->flags &= ~FTPC_FLAG_CONNECTED; } while (0) +#define FTPC_CLR_LOGGEDIN(s) do { (s)->flags &= ~FTPC_FLAG_LOGGEDIN; } while (0) +#define FTPC_CLR_MDTM(s) do { (s)->flags &= ~FTPC_FLAG_MDTM; } while (0) +#define FTPC_CLR_SIZE(s) do { (s)->flags &= ~FTPC_FLAG_SIZE; } while (0) +#define FTPC_CLR_PASV(s) do { (s)->flags &= ~FTPC_FLAG_PASV; } while (0) +#define FTPC_CLR_STOU(s) do { (s)->flags &= ~FTPC_FLAG_STOU; } while (0) +#define FTPC_CLR_CHMOD(s) do { (s)->flags &= ~FTPC_FLAG_CHMOD; } while (0) +#define FTPC_CLR_IDLE(s) do { (s)->flags &= ~FTPC_FLAG_IDLE; } while (0) +#define FTPC_CLR_INTERRUPT(s) do { (s)->flags &= ~FTPC_FLAG_INTERRUPT; } while (0) +#define FTPC_CLR_PUT(s) do { (s)->flags &= ~FTPC_FLAG_PUT; } while (0) +#define FTPC_CLR_PASSIVE(s) do { (s)->flags &= ~FTPC_FLAG_PASSIVE; } while (0) + +#define FTPC_IS_CONNECTED(s) (((s)->flags & FTPC_FLAG_CONNECTED) != 0) +#define FTPC_IS_LOGGEDIN(s) (((s)->flags & FTPC_FLAG_LOGGEDIN) != 0) +#define FTPC_HAS_MDTM(s) (((s)->flags & FTPC_FLAG_MDTM) != 0) +#define FTPC_HAS_SIZE(s) (((s)->flags & FTPC_FLAG_SIZE) != 0) +#define FTPC_HAS_PASV(s) (((s)->flags & FTPC_FLAG_PASV) != 0) +#define FTPC_HAS_STOU(s) (((s)->flags & FTPC_FLAG_STOU) != 0) +#define FTPC_HAS_CHMOD(s) (((s)->flags & FTPC_FLAG_CHMOD) != 0) +#define FTPC_HAS_IDLE(s) (((s)->flags & FTPC_FLAG_IDLE) != 0) +#define FTPC_INTERRUPTED(s) (((s)->flags & FTPC_FLAG_INTERRUPT) != 0) +#define FTPC_IS_PUT(s) (((s)->flags & FTPC_FLAG_PUT) != 0) +#define FTPC_IS_PASSIVE(s) (((s)->flags & FTPC_FLAG_PASSIVE) != 0) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure represents the state of one socket connection */ + +struct ftpc_socket_s +{ + int sd; /* Socket descriptor */ + FILE *instream; /* Incoming stream */ + FILE *outstream; /* Outgoing stream */ + struct sockaddr_in laddr; /* Local address */ + struct sockaddr_in raddr; /* Remote address */ + bool connected; /* True: socket is connected */ +}; + +/* This structure represents the state of an FTP connection */ + +struct ftpc_session_s +{ + struct in_addr addr; /* Server/proxy IP address */ + struct ftpc_socket_s cmd; /* FTP command channel */ + struct ftpc_socket_s data; /* FTP data channel */ + WDOG_ID wdog; /* Timer */ + FAR char *uname; /* Login uname */ + FAR char *pwd; /* Login pwd */ + FAR char *initdir; /* Initial remote directory */ + FAR char *homedir; /* Home directory (curdir on startup) */ + FAR char *curdir; /* Current directory */ + FAR char *prevdir; /* Previous directory */ + FAR char *rname; /* Remote file name */ + FAR char *lname; /* Local file name */ + uint8_t xfrmode; /* Previous data transfer type (See FTPC_XFRMODE_* defines) */ + uint16_t port; /* Server/proxy port number (probably 21) */ + uint16_t flags; /* Connection flags (see FTPC_FLAGS_* defines) */ + uint16_t code; /* Last 3-digit replay code */ + uint32_t replytimeo; /* Server replay timeout (ticks) */ + uint32_t conntimeo; /* Connection timeout (ticks) */ + off_t filesize; /* Total file size to transfer */ + off_t offset; /* Transfer file offset */ + off_t size; /* Number of bytes transferred */ + off_t rstrsize; /* restart size */ + + char reply[CONFIG_FTP_MAXREPLY+1]; /* Last reply string from server */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Inline Functions/Function-like Macros + ****************************************************************************/ + +#define ftpc_sockconnected(s) \ + ((s) && (s)->connected) +#define ftpc_connected(s) \ + (FTPC_IS_CONNECTED(session) && ftpc_sockconnected(&session->cmd)) +#define ftpc_loggedin(s) \ + (ftpc_connected(s) && FTPC_IS_LOGGEDIN(s)) + +#define ftpc_sockgetc(s) \ + fgetc((s)->instream) +#define ftpc_sockflush(s) \ + fflush((s)->outstream) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/* Low-level string management */ + +EXTERN void ftpc_stripcrlf(FAR char *str); +EXTERN void ftpc_stripslash(FAR const char *str); +EXTERN FAR char *ftpc_dequote(FAR const char *hostname); + +/* FTP helpers */ + +EXTERN void ftpc_reset(struct ftpc_session_s *session); +EXTERN int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...); +EXTERN int fptc_getreply(struct ftpc_session_s *session); +EXTERN void ftpc_curdir(struct ftpc_session_s *session); +EXTERN int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode); + +EXTERN int ftpc_reconnect(FAR struct ftpc_session_s *session); +EXTERN int ftpc_relogin(FAR struct ftpc_session_s *session); + +/* Socket helpers */ + +EXTERN int ftpc_sockinit(FAR struct ftpc_socket_s *sock); +EXTERN void ftpc_sockclose(FAR struct ftpc_socket_s *sock); +EXTERN int ftpc_sockconnect(FAR struct ftpc_socket_s *sock, + FAR struct sockaddr_in *addr); +EXTERN int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock, + FAR struct sockaddr_in *sa); +EXTERN int ftpc_sockaccept(FAR struct ftpc_socket_s *sock, + FAR const char *mode, bool passive); +EXTERN int ftpc_socklisten(FAR struct ftpc_socket_s *sock); +EXTERN void ftpc_sockcopy(FAR struct ftpc_socket_s *dest, + FAR const struct ftpc_socket_s *src); + +/* Socket I/O helpers */ + +EXTERN int ftpc_sockprintf(FAR struct ftpc_socket_s *sock, const char *str, ...); + +/* Timeout handlers */ + +EXTERN void ftpc_replytimeo(int argc, uint32_t arg1, ...); +EXTERN void ftpc_conntimeo(int argc, uint32_t arg1, ...); + +/* Transfer helpers */ + +EXTERN int ftpc_xfrinit(FAR struct ftpc_session_s *session); +EXTERN int ftpc_recvtext(FAR struct ftpc_session_s *session, + FAR FILE *rinstream, FAR FILE *loutstream); +EXTERN int ftpc_waitdata(FAR struct ftpc_session_s *session, + FAR FILE *stream, bool rdwait); + +EXTERN void ftpc_xfrreset(struct ftpc_session_s *session); +EXTERN int ftpc_xfrabort(FAR struct ftpc_session_s *session, + FAR FILE *stream); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H */ diff --git a/apps/netutils/ftpc/ftpc_listdir.c b/apps/netutils/ftpc/ftpc_listdir.c new file mode 100644 index 000000000..2b7706fc1 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_listdir.c @@ -0,0 +1,449 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_listdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libgen.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef void (*callback_t)(FAR const char *name, FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_abspath + * + * Description: + * Get the absolute path to a file, handling tilde expansion. + * + ****************************************************************************/ + +static FAR char *ftpc_abspath(FAR struct ftpc_session_s *session, + FAR const char *relpath); +{ + FAR char *ptr = NULL; + int ret = OK; + + /* If no relative path was provide, then use the current working directory */ + + if (!relpath) + { + return strdup(session->curdir); + } + + /* Handle tilde expansion */ + + if (relpath[0] == '~') + { + /* Is the relative path only '~' */ + + if (relpath[1] == '\0') + { + return strdup(session->home); + } + + /* No... then a '/' better follow the tilde */ + + else if (relpath[1] == '/') + { + ret = asprintf(&ptr, "%s%s", session->homedir, &relpath[1]); + } + + /* Hmmm... this prety much guaranteed to fail */ + + else + { + ptr = strdup(relpath); + } + } + + /* No tilde expansion. Check for a path relative to the current + * directory. + */ + + else if (strncmp(relpath, "./", 2) == 0) + { + ret = asprintf(&ptr, "%s%s", session->curdir, relpath+1); + } + + /* Check for an absolute path */ + + else if (relpath[0] == '/' && relpath[1] == ':' && relpath[2] == '\\') + { + ptr = strdup(relpath); + } + + /* Take a wild guess */ + + else + { + ret = asprintf(&ptr, "%s/%s", session->curdir, relpath); + } + + return ptr; +} + +/**************************************************************************** + * Name: ftpc_dircount + * + * Description: + * This callback simply counts the number of names in the directory. + * + ****************************************************************************/ + +static void ftpc_dircount(FAR const char *name, FAR void *arg) +{ + unsigned int *dircount = (unsigned int *)arg; + (*dircount)++; +} + +/**************************************************************************** + * Name: ftpc_addname + * + * Description: + * This callback adds a name to the directory listing. + * + ****************************************************************************/ + +static void ftpc_addname(FAR const char *name, FAR void *arg) +{ + FAR struct ftpc_dirlist_s *dirlist = (FAR struct ftpc_dirlist_s *)arg; + unsigned int nnames = dirlist->nnames; + dirlist->name[nnames] = strdup(name); + dirlist->nnames = nnames + 1; +} + +/**************************************************************************** + * Name: ftpc_nlstparse + * + * Description: + * Parse the NLST directory response. The NLST response consists of a + * sequence of pathnames. Each pathname is terminated by \r\n. + * + * If a pathname starts with a slash, it represents the pathname. If a + * pathname does not start with a slash, it represents the pathname obtained + * by concatenating the pathname of the directory and the pathname. + * + * IF NLST of directory /pub produces foo\r\nbar\r\n, it refers to the + * pathnames /pub/foo and /pub/bar. + * + ****************************************************************************/ + +static void ftpc_nlstparse(FAR FILE *instream, callback_t callback, + FAR void *arg) +{ + char buffer[CONFIG_FTP_MAXPATH+1]; + + /* Read every filename from the temporary file */ + + while (!feof(instream)) + { + /* Read the next line from the file */ + + if (!fgets(buffer, CONFIG_FTP_MAXPATH, instream)) + { + break; + } + + /* Remove any trailing CR-LF from the line */ + + ftpc_stripcrlf(buffer); + + /* Check for empty file names */ + + if (buffer[0] == '\0') + { + break; + } + nvdbg("File: %s\n", buffer); + + /* Perform the callback operation */ + + callback(buffer, arg); + } +} + +/**************************************************************************** + * Name: ftpc_recvdir + * + * Description: + * Get the directory listing. + * + ****************************************************************************/ + +static int ftpc_recvdir(FAR struct ftpc_session_s *session, + FAR FILE *outstream) +{ + int ret; + + /* Verify that we are still connected to the server */ + + if (!ftpc_connected(session)) + { + ndbg("Not connected to server\n"); + return ERROR; + } + + /* Setup for the transfer */ + + ftpc_xfrreset(session); + ret = ftpc_xfrinit(session); + if (ret != OK) + { + return ERROR; + } + + /* Send the "NLST" command */ + + ret = ftpc_cmd(session, "NLST"); + if (ret != OK) + { + return ERROR; + } + + /* Accept the connection from the server */ + + ret = ftpc_sockaccept(&session->data, "r", FTPC_IS_PASSIVE(session)); + if (ret != OK) + { + ndbg("ftpc_sockaccept() failed: %d\n", errno); + return ERROR; + } + + /* Receive the NLST response */ + + ret = ftpc_recvtext(session, session->data.instream, outstream); + ftpc_sockclose(&session->data); + if (ret != OK) + { + return ERROR; + } + + /* Get the server reply */ + + fptc_getreply(session); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_listdir + * + * Description: + * Get a simple directory listing using NLST: + * + * NLST [<SP> <pathname>] <CRLF> + * + * We could do much, much more here using the LIST or MLST/MLSD commands, + * but the parsing is a bitch. See http://cr.yp.to/ftpparse.html + * + * NOTE: We expect to receive only well structured directory paths. Tilde + * expansion "~/xyz" and relative pathes (abc/def) because we do have + * special knowledge about the home and current directories. But otherwise + * the pathes are expected to be pre-sanitized: No . or .. in paths, + * no '//' in paths, etc. + * + ****************************************************************************/ + +FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle, + FAR const char *dirpath) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct ftpc_dirlist_s *dirlist; + FILE *filestream; + FAR char *abspath; + FAR char *tmpfname; + bool iscurdir; + unsigned int nnames; + int allocsize; + int ret; + + /* Get the absolute path to the directory */ + + abspath = ftpc_abspath(session, dirpath); + ftpc_stripslash(abspath); + + /* Is the directory also the remote current working directory? */ + + iscurdir = (strcmp(abspath, session->curdir) == 0); + + /* Create a temporary file to hold the directory listing */ + + asprintf(&tmpfname, "%s/TMP%s.dat", CONFIG_FTP_TMPDIR, getpid()); + filestream = fopen(tmpfname, "w+"); + if (!filestream) + { + ndbg("Failed to create %s: %d\n", tmpfname, errno); + free(abspath); + free(tmpfname); + return NULL; + } + + /* "CWD" first so that we get the directory contents, not the + * directory itself. + */ + + if (!iscurdir) + { + ret = ftpc_cmd(session, "CWD %s", abspath); + if (ret != OK) + { + ndbg("CWD to %s failed\n", abspath); + } + } + + /* Send the NLST command with no arguments to get the entire contents of + * the directory. + */ + + ret = ftpc_recvdir(session, filestream); + + /* Go back to the correct current working directory */ + + if (!iscurdir) + { + int tmpret = ftpc_cmd(session, "CWD %s", session->curdir); + if (tmpret != OK) + { + ndbg("CWD back to to %s failed\n", session->curdir); + } + } + + /* Did we successfully receive the directory listing? */ + + dirlist = NULL; + if (ret == OK) + { + /* Count the number of names in the temporary file */ + + rewind(filestream); + ftpc_nlstparse(filestream, ftpc_dircount, &nnames); + if (!nnames) + { + ndbg("Nothing found in directory\n"); + goto errout; + } + + /* Allocate and initialize a directory container */ + + allocsize = SIZEOF_FTPC_DIRLIST(nnames); + dirlist = (struct ftpc_dirlist_s *)malloc(allocsize); + if (!dirlist) + { + ndbg("Failed to allocate dirlist\n"); + goto errout; + } + dirlist->nnames = 0; + + /* Then copy all of the directory strings into the container */ + + rewind(filestream); + ftpc_nlstparse(filestream, ftpc_dircount, &nnames); + DEBUGASSERT(nnames == dirlist->nnames); + } + +errout: + fclose(filestream); + free(abspath); + unlink(tmpfname); + free(tmpfname); + return dirlist; +} + +/**************************************************************************** + * Name: ftpc_dirfree + * + * Description: + * Release the allocated directory listing. + * + ****************************************************************************/ + +void ftpc_dirfree(FAR struct ftpc_dirlist_s *dirlist) +{ + int i; + + if (dirlist) + { + /* Free each directory name in the directory container */ + + for (i = 0; i < dirlist->nnames; i++) + { + /* NULL means that the caller stole the string */ + + if (dirlist->name[i]) + { + free(dirlist->name[i]); + } + } + + /* Then free the container itself */ + + free(dirlist); + } +} + diff --git a/apps/netutils/ftpc/ftpc_login.c b/apps/netutils/ftpc/ftpc_login.c new file mode 100644 index 000000000..f2697dde1 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_login.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_login.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_login + * + * Description: + * Log into the server + * + ****************************************************************************/ + +int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int err; + int ret; + + /* Verify that we are connected to a server */ + + if (!ftpc_connected(session)) + { + ndbg("Not connected\n"); + err = ENOTCONN; + goto errout_with_err; + } + + /* Verify that we are not already logged in to the server */ + + if (ftpc_loggedin(session)) + { + ndbg("Already logged in\n"); + err = EINVAL; + goto errout_with_err; + } + + /* Save the login parameter */ + + session->uname = decode_rfc1738(login->uname); + session->pwd = decode_rfc1738(login->pwd); + session->initdir = decode_rfc1738(login->rdir); + + /* Is passive mode requested? */ + + FTPC_CLR_PASSIVE(session); + if (login->pasv) + { + FTPC_SET_PASSIVE(session); + } + + /* The (Re-)login to the server */ + + ret = ftpc_relogin(session); + if (ret != OK) + { + ndbg("login failed: %d\n", errno); + goto errout; + } + + return OK; + +errout_with_err: + set_errno(err); +errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_relogin + * + * Description: + * Log in again after a loss of connection + * + ****************************************************************************/ + +int ftpc_relogin(FAR struct ftpc_session_s *session) +{ + int err; + int ret; + + /* Log into the server */ + + FTPC_CLR_LOGGEDIN(session); + ret = ftpc_cmd(session, "USER %s", session->uname); + if (ret != OK) + { + ndbg("USER %s cmd failed: %d\n", session->uname, errno); + return ERROR; + } + + ret = ftpc_cmd(session, "PASS %s", session->pwd); + if (ret != OK) + { + ndbg("PASS %s cmd failed: %d\n", session->pwd, errno); + return ret; + } + + FTPC_SET_LOGGEDIN(session); + session->homedir = ftpc_pwd((SESSION)session); + session->curdir = strdup(session->homedir); + session->prevdir = strdup(session->homedir); + if (session->initdir) + { + ftpc_chdir((SESSION)session, session->initdir); + } + + return OK; +} diff --git a/apps/netutils/ftpc/ftpc_mkdir.c b/apps/netutils/ftpc/ftpc_mkdir.c new file mode 100644 index 000000000..d11466112 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_mkdir.c @@ -0,0 +1,93 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_mkdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <string.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_mkdir + * + * Description: + * Creates the named directory on the remote server. + * + ****************************************************************************/ + +int ftpc_mkdir(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + char *ptr; + int ret; + + ptr = strdup(path); + ftpc_stripslash(ptr); + + ret = ftpc_cmd(session, "MKD %s", ptr); + free(ptr); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_noop.c b/apps/netutils/ftpc/ftpc_noop.c new file mode 100644 index 000000000..5e6874f02 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_noop.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_noop.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_noop + * + * Description: + * No operation command. Using NOOP allows us to make sure that commands + * are passed over the control connection without changing the status of + * any data transaction or server status. This is useful for (1) + * maintaining connections during long IDLE times and (2) It can also be + * used as a harmless way of detecting timeouts. + * + ****************************************************************************/ + +int ftpc_noop(SESSION handle) +{ + return ftpc_cmd((FAR struct ftpc_session_s *)handle, "NOOP"); +} diff --git a/apps/netutils/ftpc/ftpc_putfile.c b/apps/netutils/ftpc/ftpc_putfile.c new file mode 100644 index 000000000..c05112402 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_putfile.c @@ -0,0 +1,406 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_putfile.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libgen.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_waitoutput + * + * Description: + * Wait to send data. + * + ****************************************************************************/ + +static int ftpc_waitoutput(FAR struct ftpc_session_s *session) +{ + int ret; + + do + { + ret = ftpc_waitdata(session, session->data.outstream, false); + if (ret < 0) + { + return ERROR; + } + } + while(ret == 0); + return OK; +} + +/**************************************************************************** + * Name: ftpc_sendbinary + * + * Description: + * Send a binary file to the remote host. + * + ****************************************************************************/ + +static int ftpc_sendbinary(FAR struct ftpc_session_s *session, + FAR FILE *linstream, FILE *routstream) +{ + FAR char *buf; + ssize_t nread; + ssize_t nwritten; + int ret = OK; + + buf = (char *)malloc(CONFIG_FTP_BUFSIZE); + while (!feof(linstream)) + { + nread = fread(buf, sizeof(char), CONFIG_FTP_BUFSIZE, linstream); + if (nread <= 0) + { + (void)ftpc_xfrabort(session, linstream); + ret = ERROR; + break; + } + + if (ftpc_waitoutput(session) != 0) + { + ret = ERROR; + break; + } + + nwritten = fwrite(buf, sizeof(char), nread, routstream); + if (nwritten != nread) + { + (void)ftpc_xfrabort(session, routstream); + ret = ERROR; + break; + } + + session->size += nread; + } + + free(buf); + return ret; +} + +/**************************************************************************** + * Name: ftpc_sendtext + * + * Description: + * Send a text file to the remote host. + * + ****************************************************************************/ + +static int ftpc_sendtext(FAR struct ftpc_session_s *session, + FAR FILE *linstream, FAR FILE *routstream) +{ + char *buf = (char *)malloc(CONFIG_FTP_BUFSIZE); + int c; + int ret = OK; + + while((c = fgetc(linstream)) != EOF) + { + if (ftpc_waitoutput(session) != 0) + { + break; + } + + if (c == '\n') + { + if (fputc('\r', routstream) == EOF) + { + (void)ftpc_xfrabort(session, routstream); + ret = ERROR; + break; + } + + session->size++; + } + + if (fputc(c, routstream) == EOF) + { + (void)ftpc_xfrabort(session, routstream); + ret = ERROR; + break; + } + + session->size++; + } + + free(buf); + return ret; +} + +/**************************************************************************** + * Name: ftpc_sendfile + * + * Description: + * Send the file to the remote host. + * + ****************************************************************************/ + +static int ftpc_sendfile(struct ftpc_session_s *session, const char *path, + FILE *stream, uint8_t how, uint8_t xfrmode) +{ + long offset = session->offset; + int ret; + + session->offset = 0; + + /* Were we asked to store a file uniquely? Does the host support the STOU + * command? + */ + + if (how == FTPC_PUT_UNIQUE && !FTPC_HAS_STOU(session)) + { + /* We cannot store a file uniquely */ + + return ERROR; + } + + ftpc_xfrreset(session); + FTPC_SET_PUT(session); + + /* Initialize for the transfer */ + + ret = ftpc_xfrinit(session); + if (ret != OK) + { + return ERROR; + } + + ftpc_xfrmode(session, xfrmode); + + if (offset > 0) + { + ret = ftpc_cmd(session, "REST %ld", offset); + session->size = offset; + session->rstrsize = offset; + } + + switch(how) + { + case FTPC_PUT_UNIQUE: + ret = ftpc_cmd(session, "STOU %s", path); + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* The host does not support the STOU command */ + + FTPC_CLR_STOU(session); + } + break; + + case FTPC_PUT_APPEND: + ret = ftpc_cmd(session, "APPE %s", path); + break; + + case FTPC_PUT_NORMAL: + default: + ret = ftpc_cmd(session, "STOR %s", path); + break; + } + + if (how == FTPC_PUT_UNIQUE) + { + /* Determine the remote filename */ + + char *str = strstr(session->reply, " for "); + if (str) + { + int len; + + str += 5; + len = strlen(str); + if (len) + { + free(session->lname); + if (*str == '\'') + { + session->lname = strndup(str+1, len-3); + } + else + { + session->lname = strndup(str, len-1); + nvdbg("parsed unique filename as '%s'\n", session->lname); + } + } + } + } + + ret = ftpc_sockaccept(&session->data, "w", FTPC_IS_PASSIVE(session)); + if (ret != OK) + { + ndbg("Data connection not accepted\n"); + return ERROR; + } + + if (xfrmode == FTPC_XFRMODE_ASCII) + { + ret = ftpc_sendbinary(session, stream, session->data.instream); + } + else + { + ret = ftpc_sendtext(session, stream, session->data.instream); + } + + ftpc_sockflush(&session->data); + ftpc_sockclose(&session->data); + + if (ret == 0) + { + fptc_getreply(session); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_putfile + * + * Description: + * Put a file on the remote host. + * + ****************************************************************************/ + +int ftp_putfile(SESSION handle, const char *lname, const char *rname, + uint8_t how, uint8_t xfrmode) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct stat statbuf; + FILE *finstream; + int ret; + + /* Make sure that the local file exists */ + + ret = stat(lname, &statbuf); + if (ret != OK) + { + ndbg("stat() failed: %d\n", errno); + return ERROR; + } + + /* Make sure that the local name does not refer to a directory */ + + if (S_ISDIR(statbuf.st_mode)) + { + ndbg("%s is a directory\n", lname); + return ERROR; + } + + /* Open the local file for reading */ + + finstream = fopen(lname, "r"); + if (!finstream == 0) + { + ndbg("fopen() failed: %d\n", errno); + return ERROR; + } + + /* Configure for the transfer */ + + session->filesize = statbuf.st_size; + free(session->rname); + free(session->lname); + session->rname = strdup(lname); + session->lname = strdup(rname); + + /* Are we resuming a transfer? */ + + session->offset = 0; + if (how == FTPC_PUT_RESUME) + { + /* Yes... Get the size of the file. This will only work if the + * server supports the SIZE command. + */ + + session->offset = ftpc_filesize(session, rname); + if (session->offset == (off_t)ERROR) + { + ndbg("Failed to get size of remote file: %s\n", rname); + } + else + { + /* Seek to the offset in the file corresponding to the size + * that we have already sent. + */ + + ret = fseek(finstream, session->offset, SEEK_SET); + if (ret != OK) + { + ndbg("fseek failed: %d\n", errnoo); + fclose(finstream); + return ERROR; + } + } + } + + ret = ftpc_sendfile(session, rname, finstream, how, xfrmode); + fclose(finstream); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_pwd.c b/apps/netutils/ftpc/ftpc_pwd.c new file mode 100644 index 000000000..f6bde0e13 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_pwd.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_pwd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <string.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_pwd + * + * Descripton: + * Returns the current working directory on the remote server. + * + ****************************************************************************/ + +FAR char *ftpc_pwd(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + FAR char *start; + FAR char *end; + FAR char *pwd; + FAR char *ptr; + int ret; + + ret = ftpc_cmd(session, "PWD"); + start = strchr(session->reply, '\"'); + if (!start) + { + ndbg("Opening quote not found\n"); + return NULL; + } + + start++; + end = strchr(start, '\"'); + if (!end) + { + ndbg("Clsoing quote not found\n"); + return NULL; + } + + pwd = (char *)malloc(end-start+1); + strncpy(pwd, start, end-start); + ftpc_stripslash(pwd); + + /* Change DOS style directory separator ('\') to UNIX style ('/') */ + + for (ptr = pwd; *ptr; ptr++) + { + if (*ptr == '\\') + { + *ptr = '/'; + } + } + return pwd; +} diff --git a/apps/netutils/ftpc/ftpc_quit.c b/apps/netutils/ftpc/ftpc_quit.c new file mode 100644 index 000000000..daae04e88 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_quit.c @@ -0,0 +1,92 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_quit.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <time.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_quit + * + * Description: + * Ends the FTP session with the remote computer and exits ftp + * + ****************************************************************************/ + +int ftpc_quit(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret = OK; + + if (ftpc_connected(session)) + { + session->replytimeo = 10 * CLOCKS_PER_SEC; + ret = ftpc_cmd(session, "QUIT"); + } + + ftpc_disconnect(handle); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_rename.c b/apps/netutils/ftpc/ftpc_rename.c new file mode 100644 index 000000000..c1a80c289 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_rename.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_rename.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <string.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_rename + * + * Description: + * Rename a file on the remote server. + * + ****************************************************************************/ + +int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + char *oldcopy; + char *newcopy; + int ret; + + oldcopy = strdup(oldname); + ftpc_stripslash(oldcopy); + ret = ftpc_cmd(session, "RNFR %s", oldcopy); + if (ret != OK) + { + free(oldcopy); + return ERROR; + } + + newcopy = strdup(newname); + ftpc_stripslash(newcopy); + ret = ftpc_cmd(session, "RNTO %s", newcopy); + + free(oldcopy); + free(newcopy); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_response.c b/apps/netutils/ftpc/ftpc_response.c new file mode 100644 index 000000000..3bf1ee54b --- /dev/null +++ b/apps/netutils/ftpc/ftpc_response.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_response.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_response + * + * Description: + * Return the response string from the last command. This is allocated + * memory that must be freed using free() when it is no longer needed. + * + ****************************************************************************/ + +FAR char *ftpc_response(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + return strndup(session->reply, CONFIG_FTP_MAXREPLY); +} diff --git a/apps/netutils/ftpc/ftpc_rmdir.c b/apps/netutils/ftpc/ftpc_rmdir.c new file mode 100644 index 000000000..caa50392f --- /dev/null +++ b/apps/netutils/ftpc/ftpc_rmdir.c @@ -0,0 +1,92 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_rmdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <string.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_rmdir + * + * Description: + * Deletes the named directory on the remote server. + * + ****************************************************************************/ +int ftpc_rmdir(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + char *ptr; + int ret; + + ptr = strdup(path); + ftpc_stripslash(ptr); + + ret = ftpc_cmd(session, "RMD %s", ptr); + free(ptr); + return ret; +} + diff --git a/apps/netutils/ftpc/ftpc_socket.c b/apps/netutils/ftpc/ftpc_socket.c new file mode 100644 index 000000000..500f20995 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_socket.c @@ -0,0 +1,390 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_socket.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/socket.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <debug.h> +#include <errno.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_sockinit + * + * Description: + * Initialize a socket. Create the socket and "wrap" it as C standard + * incoming and outgoing streams. + * + ****************************************************************************/ + +int ftpc_sockinit(FAR struct ftpc_socket_s *sock) +{ + int dupsd; + + /* Initialize the socket structure */ + + memset(sock, 0, sizeof(struct ftpc_socket_s)); + sock->raddr.sin_family = AF_INET; + + /* Create a socket descriptor */ + + sock->sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock->sd < 0) + { + ndbg("socket() failed: %d\n", errno); + goto errout; + } + + /* 'dup' the socket descriptor to create an independent input stream */ + + dupsd = dup(sock->sd); + if (dupsd < 0) + { + ndbg("socket() failed: %d\n", errno); + goto errout_with_sd; + } + + /* Call fdopen to "wrap" the input stream with C buffered I/O */ + + sock->instream = fdopen(dupsd, "r"); + if (!sock->instream) + { + ndbg("fdopen() failed: %d\n", errno); + close(dupsd); + goto errout_with_sd; + } + + /* 'dup' the socket descriptor to create an independent output stream */ + + dupsd = dup(sock->sd); + if (dupsd < 0) + { + ndbg("socket() failed: %d\n", errno); + goto errout_with_instream; + } + + /* Call fdopen to "wrap" the output stream with C buffered I/O */ + + sock->outstream = fdopen(dupsd, "w"); + if (!sock->outstream) + { + ndbg("fdopen() failed: %d\n", errno); + close(dupsd); + goto errout_with_instream; + } + + return OK; + +errout_with_instream: + fclose(sock->instream); +errout_with_sd: + close(sock->sd); +errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_sockclose + * + * Description: + * Close a socket + * + ****************************************************************************/ + +void ftpc_sockclose(struct ftpc_socket_s *sock) +{ + fclose(sock->instream); + fclose(sock->outstream); + close(sock->sd); + memset(sock, 0, sizeof(struct ftpc_socket_s)); +} + +/**************************************************************************** + * Name: ftpc_sockconnect + * + * Description: + * Connect the socket to the host + * + ****************************************************************************/ + +int ftpc_sockconnect(struct ftpc_socket_s *sock, struct sockaddr_in *addr) +{ + int ret; + + /* Connect to the socket */ + + ret = connect(sock->sd, (struct sockaddr *)addr, sizeof(struct sockaddr)); + if (ret < 0) + { + ndbg("connect() failed: %d\n", errno); + close(sock->sd); + return ERROR; + } + + /* Get the local address of the socket */ + + ret = ftpc_sockgetsockname(sock, &sock->laddr); + if (ret < 0) + { + ndbg("ftpc_sockgetsockname() failed: %d\n", errno); + close(sock->sd); + return ERROR; + } + sock->connected = true; + + return OK; +} + +/**************************************************************************** + * Name: ftpc_sockcopy + * + * Description: + * Copy the socket state from one location to another. + * + ****************************************************************************/ + +void ftpc_sockcopy(FAR struct ftpc_socket_s *dest, + FAR const struct ftpc_socket_s *src) +{ + memcpy(&dest->raddr, &src->raddr, sizeof(struct sockaddr_in)); + memcpy(&dest->laddr, &src->laddr, sizeof(struct sockaddr_in)); + dest->connected = ftpc_sockconnected(src); +} + +/**************************************************************************** + * Name: ftpc_sockaccept + * + * Description: + * Accept a connection from the server. + * + ****************************************************************************/ + +int ftpc_sockaccept(struct ftpc_socket_s *sock, const char *mode, bool passive) +{ + struct sockaddr addr; + socklen_t addrlen; + int dupsd; + int sd; + + /* In active mode FTP the client connects from a random port (N>1023) to the + * FTP server's command port, port 21. Then, the client starts listening to + * port N+1 and sends the FTP command PORT N+1 to the FTP server. The server + * will then connect back to the client's specified data port from its local + * data port, which is port 20. In passive mode FTP the client initiates + * both connections to the server, solving the problem of firewalls filtering + * the incoming data port connection to the client from the server. When + * opening an FTP connection, the client opens two random ports locally + * (N>1023 and N+1). The first port contacts the server on port 21, but + * instead of then issuing a PORT command and allowing the server to connect + * back to its data port, the client will issue the PASV command. The result + * of this is that the server then opens a random unprivileged port (P > + * 1023) and sends the PORT P command back to the client. The client then + * initiates the connection from port N+1 to port P on the server to transfer + * data. + */ + + if (!passive) + { + addrlen = sizeof(addr); + sd = accept(sock->sd, &addr, &addrlen); + close(sock->sd); + if (sd == -1) + { + ndbg("accept() failed: %d\n", errno); + sock->sd = -1; + return ERROR; + } + + sock->sd = sd; + memcpy(&sock->laddr, &addr, sizeof(sock->laddr)); + } + + /* Create in/out C buffer I/O streams on the cmd channel */ + + fclose(sock->instream); + fclose(sock->outstream); + + /* Dup the socket descriptor and create the incoming stream */ + + dupsd = dup(sock->sd); + if (dupsd < 0) + { + ndbg("dup() failed: %d\n", errno); + goto errout_with_sd; + } + + sock->instream = fdopen(dupsd, mode); + if (!sock->instream) + { + ndbg("fdopen() failed: %d\n", errno); + close(dupsd); + goto errout_with_sd; + } + + /* Dup the socket descriptor and create the outgoing stream */ + + dupsd = dup(sock->sd); + if (dupsd < 0) + { + ndbg("dup() failed: %d\n", errno); + goto errout_with_instream; + } + + sock->outstream = fdopen(dupsd, mode); + if (!sock->outstream) + { + ndbg("fdopen() failed: %d\n", errno); + close(dupsd); + goto errout_with_instream; + } + + return OK; + +errout_with_instream: + fclose(sock->instream); +errout_with_sd: + close(sock->sd); + sock->sd = -1; + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_socklisten + * + * Description: + * Bind the socket to local address and wait for connection from the server. + * + ****************************************************************************/ + +int ftpc_socklisten(struct ftpc_socket_s *sock) +{ + unsigned int addrlen = sizeof(sock->laddr); + int ret; + + /* Bind the local socket to the local address */ + + sock->laddr.sin_port = 0; + ret = bind(sock->sd, (struct sockaddr *)&sock->laddr, addrlen); + if (ret < 0) + { + ndbg("bind() failed: %d\n", errno); + return ERROR; + } + + /* Wait for the connection to the server */ + + if (listen(sock->sd, 1) == -1) + { + return ERROR; + } + + /* Then get the local address selected by NuttX */ + + ret = ftpc_sockgetsockname(sock, &sock->laddr); + return ret; +} + +/**************************************************************************** + * Name: ftpc_sockprintf + * + * Description: + * printf to a socket stream + * + ****************************************************************************/ + +int ftpc_sockprintf(struct ftpc_socket_s *sock, const char *str, ...) +{ + va_list ap; + int r; + + va_start(ap, str); + r = vfprintf(sock->outstream, str, ap); + va_end(ap); + return r; +} + +/**************************************************************************** + * Name: ftpc_sockgetsockname + * + * Description: + * Get the address of the local socket + * + ****************************************************************************/ + +int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock, + FAR struct sockaddr_in *addr) +{ + unsigned int len = sizeof(struct sockaddr_in); + int ret; + + ret = getsockname(sock->sd, (struct sockaddr *)addr, &len); + if (ret < 0) + { + ndbg("getsockname failed: %d\n", errno); + return ERROR; + } + return OK; +} diff --git a/apps/netutils/ftpc/ftpc_transfer.c b/apps/netutils/ftpc/ftpc_transfer.c new file mode 100644 index 000000000..bce30e302 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_transfer.c @@ -0,0 +1,400 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_transfer.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/stat.h> +#include <sys/time.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <poll.h> +#include <ctype.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftp_pasvmode + * + * Description: + * Enter passive mode. + * + * In active mode FTP the client connects from a random port (N>1023) to the + * FTP server's command port, port 21. Then, the client starts listening to + * port N+1 and sends the FTP command PORT N+1 to the FTP server. The server + * will then connect back to the client's specified data port from its local + * data port, which is port 20. In passive mode FTP the client initiates + * both connections to the server, solving the problem of firewalls filtering + * the incoming data port connection to the client from the server. When + * opening an FTP connection, the client opens two random ports locally + * (N>1023 and N+1). The first port contacts the server on port 21, but + * instead of then issuing a PORT command and allowing the server to connect + * back to its data port, the client will issue the PASV command. The result + * of this is that the server then opens a random unprivileged port (P > + * 1023) and sends the PORT P command back to the client. The client then + * initiates the connection from port N+1 to port P on the server to transfer + * data. + * + ****************************************************************************/ + +static int ftp_pasvmode(struct ftpc_session_s *session, + uint8_t addrport[6]) +{ + int tmpap[6]; + char *ptr; + int nscan; + int ret; + int i; + + /* Does this host support the PASV command */ + + if (!FTPC_HAS_PASV(session)) + { + ndbg("Host doesn't support passive mode\n"); + return ERROR; + } + + /* Request passive mode */ + + ret = ftpc_cmd(session, "PASV"); + if (ret < 0 || !ftpc_connected(session)) + { + return ERROR; + } + + /* Skip over any leading stuff before address begins */ + + ptr = session->reply + 4; + while (!isdigit((int)*ptr)) + { + ptr++; + } + + /* The response is then 6 integer values: four representing the + * IP address and two representing the port number. + */ + + nscan = sscanf(ptr, "%d,%d,%d,%d,%d,%d", + &tmpap[0], &tmpap[1], &tmpap[2], + &tmpap[3], &tmpap[4], &tmpap[5]); + if (nscan != 6) + { + ndbg("Error parsing PASV reply: '%s'\n", session->reply); + return ERROR; + } + + /* Then copy the sscanf'ed values as bytes */ + + + for (i = 0; i < 6; i++) + { + addrport[i] = (uint8_t)(tmpap[i] & 0xff); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_xfrinit + * + * Description: + * Perform common transfer setup logic. + * + ****************************************************************************/ + +int ftpc_xfrinit(FAR struct ftpc_session_s *session) +{ + struct sockaddr_in addr; + uint8_t addrport[6]; + uint8_t *paddr; + uint8_t *pport; + int ret; + + /* We must be connected to initiate a transfer */ + + if (!ftpc_connected(session)) + { + goto errout; + } + + /* Initialize the data channel */ + + ret = ftpc_sockinit(&session->data); + if (ret != OK) + { + ndbg("ftpc_sockinit() failed: %d\n", errno); + goto errout; + } + + /* Duplicate the address and connection information of the command channel */ + + ftpc_sockcopy(&session->data, &session->cmd); + + /* Should we enter passive mode? */ + + if (FTPC_IS_PASSIVE(session)) + { + /* Yes.. going passive. */ + + ret = ftp_pasvmode(session, addrport); + if (ret != OK) + { + goto errout_with_data; + } + } + + /* Configure the data socket */ + + ftpc_sockgetsockname(&session->cmd, &addr); + memcpy(&addr.sin_addr, addrport, (size_t)4); + memcpy(&addr.sin_port, addrport+4, (size_t)2); + + /* Connect the data socket */ + + ret = ftpc_sockconnect(&session->data, &addr); + if (ret < 0) + { + ndbg("ftpc_sockconnect() failed: %d\n", errno); + goto errout_with_data; + } + else + { + /* Wait for the connection to be established */ + + ftpc_socklisten(&session->data); + + /* Then send our local data channel address to the server */ + + paddr = (uint8_t *)&session->data.laddr.sin_addr; + pport = (uint8_t *)&session->data.laddr.sin_port; + + ret = ftpc_cmd(session, "PORT %d,%d,%d,%d,%d,%d", + paddr[0], paddr[1], paddr[2], + paddr[3], pport[0], pport[1]); + if (ret < 0) + { + ndbg("ftpc_cmd() failed: %d\n", errno); + goto errout_with_data; + } + } + return OK; + + errout_with_data: + ftpc_sockclose(&session->data); + errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_xfrreset + * + * Description: + * Reset transfer variables + * + ****************************************************************************/ + +void ftpc_xfrreset(struct ftpc_session_s *session) +{ + session->size = 0; + session->flags &= ~FTPC_XFER_FLAGS; + session->rstrsize = 0; +} + +/**************************************************************************** + * Name: ftpc_xfrmode + * + * Description: + * Select ASCII or Binary transfer mode + * + ****************************************************************************/ + +int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode) +{ + int ret; + + DEBUGASSERT(xfrmode != FTPC_XFRMODE_UNKNOWN); + if (session->xfrmode != xfrmode) + { + ret = ftpc_cmd(session, "TYPE %c", xfrmode == FTPC_XFRMODE_ASCII ? 'A' : 'I'); + session->xfrmode = xfrmode; + } + return OK; +} + +/**************************************************************************** + * Name: ftpc_xfrabort + * + * Description: + * Abort a transfer in progress + * + ****************************************************************************/ + +int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream) +{ + char buffer[CONFIG_FTP_BUFSIZE]; + FAR struct pollfd fds; + int ret; + + /* Make sure that we are still connected */ + + if (!ftpc_connected(session)) + { + return ERROR; + } + + /* Check if there is data waiting to be read from the cmd channel */ + + fds.fd = session->cmd.sd; + fds.events = POLLIN; + ret = poll(&fds, 1, 0); + if (ret > 0) + { + /* Read data from command channel */ + + nvdbg("Flush cmd channel data\n"); + while (stream && fread(buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0); + return OK; + } + + FTPC_SET_INTERRUPT(session); + + /* Send the Telnet interrupt sequence to abort the transfer: + * <IAC IP><IAC DM>ABORT<CR><LF> + */ + + ndbg("Telnet ABORt sequence\n"); + ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_IP); /* Interrupt process */ + ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_DM); /* Telnet synch signal */ + ftpc_sockprintf(&session->cmd, "ABOR\r\n"); /* Abort */ + ftpc_sockflush(&session->cmd); + + /* Read remaining bytes from connection */ + + while (stream && fread(buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0); + while(stream && fread(buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0) + + /* Get the ABORt reply */ + + fptc_getreply(session); + + /* Expected replys are: "226 Closing data connection" or + * "426 Connection closed; transfer aborted" + */ + + if (session->code != 226 && session->code != 426) + { + nvdbg("Expected 226 or 426 reply\n"); + } + else + { + /* Get the next reply */ + + fptc_getreply(session); + + /* Expected replys are: or "225 Data connection open; no transfer in progress" + * "226 Closing data connection" + */ + + if (session->code != 226 && session->code != 225) + { + nvdbg("Expected 225 or 226 reply\n"); + } + } + + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_waitdata + * + * Description: + * Wait for dta to be available on the provided stream. + * + ****************************************************************************/ + +int ftpc_waitdata(FAR struct ftpc_session_s *session, FAR FILE *stream, bool rdwait) +{ + FAR struct pollfd fds; + int ret; + + /* Check the stream to see if it has input OR is ready for output */ + + fds.fd = fileno(stream); + fds.events = rdwait ? POLLIN : POLLOUT; + ret = poll(&fds, 1, 10*1000); + if (ret < 0) + { + if (errno == EINTR) + { + return OK; + } + return ERROR; + } + + return ret; +} + + + diff --git a/apps/netutils/ftpc/ftpc_unlink.c b/apps/netutils/ftpc/ftpc_unlink.c new file mode 100644 index 000000000..3a49374de --- /dev/null +++ b/apps/netutils/ftpc/ftpc_unlink.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_unlink.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_unlink + * + * Descripton: + * Delete the given file from the remote server. + * + ****************************************************************************/ + +int ftpc_unlink(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + ret = ftpc_cmd(session, "DELE %s", path); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_utils.c b/apps/netutils/ftpc/ftpc_utils.c new file mode 100644 index 000000000..46944e4b2 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_utils.c @@ -0,0 +1,251 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_utils.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_nibble + * + * Description: + * Convert a ASCII hex 'digit' to binary + * + ****************************************************************************/ + +int ftpc_nibble(char ch) +{ + if (ch >= '0' && ch <= '9') + { + return (unsigned int)ch - '0'; + } + else if (ch >= 'A' && ch <= 'F') + { + return (unsigned int)ch - 'A' + 10; + } + else if (ch >= 'a' && ch <= 'f') + { + return (unsigned int)ch - 'a' + 10; + } + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_reset + * + * Description: + * Reset the FTP session. + * + ****************************************************************************/ + +void ftpc_reset(struct ftpc_session_s *session) +{ + ftpc_sockclose(&session->data); + ftpc_sockclose(&session->cmd); + free(session->uname); + session->uname = NULL; + free(session->pwd); + session->pwd = NULL; + free(session->initdir); + session->initdir = NULL; + session->flags = FTPC_FLAGS_INIT; + session->xfrmode = FTPC_XFRMODE_UNKNOWN; + session->code = 0; + session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; +} + +/**************************************************************************** + * Name: ftpc_curdir + * + * Description: + * Update the current working directory + * + ****************************************************************************/ + +void ftpc_curdir(struct ftpc_session_s *session) +{ + free(session->prevdir); + session->prevdir = session->curdir; + session->curdir = ftpc_pwd((SESSION)session); +} + +/**************************************************************************** + * Name: ftpc_stripcrlf + * + * Description: + * Strip any trailing carriage returns or line feeds from a string. + * + ****************************************************************************/ + +void ftpc_stripcrlf(FAR char *str) +{ + FAR char *ptr; + int len; + + if (str) + { + len = strlen(str); + if (len > 0) + { + ptr = str + len - 1; + while (*ptr == '\r' || *ptr == '\n') + { + *ptr = '\0'; + ptr--; + } + } + } +} + +/**************************************************************************** + * Name: ftpc_stripslash + * + * Description: + * Strip any trailing slashes from a string. + * + ****************************************************************************/ + +FAR char *ftpc_stripslash(FAR char *str) +{ + FAR char *ptr; + + if (!str || !*str) + return str; + + ptr = strchr(str, 0); + if(!ptr) + return str; + ptr--; + if(*ptr == '/') { + if(ptr != str) /* root directory */ + *ptr = 0; + } + return str; +} + +/**************************************************************************** + * Name: ftpc_stripslash + * + * Description: + * Convert quoted hexadecimal constants to binary values. + * + ****************************************************************************/ + +FAR char *ftpc_dequote(FAR const char *str) +{ + FAR char *allocstr = NULL; + FAR char *ptr; + int ms; + int ls; + int len; + + if (str) + { + /* Allocate space for a modifiable copy of the string */ + + len = strlen(str); + allocstr = (FAR char*)malloc(len+1); + if (allocstr) + { + /* Search the string */ + + ptr = allocstr; + while (*str) + { + /* Check for a quoted hex value */ + + if (str[0] == '%') + { + /* Extract the hex value */ + + ms = ftpc_nibble(str[1]); + if (ms >= 0) + { + ls = ftpc_nibble(str[2]); + if (ls >= 0) + { + /* Save the binary value and skip ahead by 3 */ + + *ptr++ = (char)(ms << 8 | ls); + str += 3; + continue; + } + } + } + + /* Just transfer the character */ + + *ptr++ = *str++; + } + + /* NUL terminate */ + + *ptr = '\0'; + } + } + + return allocstr; +} |