summaryrefslogtreecommitdiff
path: root/apps/netutils/ftpc/ftpc_socket.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-06-01 19:15:14 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-06-01 19:15:14 +0000
commitc505c3eb243de07b8a59d71b5dbe5683ee9466f4 (patch)
tree67da5ab592d26f8901fe47da44d5f21967277d1b /apps/netutils/ftpc/ftpc_socket.c
parent7130c3c2de1b2e7647584b400367fbaae75d93a4 (diff)
downloadnuttx-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/ftpc_socket.c')
-rw-r--r--apps/netutils/ftpc/ftpc_socket.c390
1 files changed, 390 insertions, 0 deletions
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;
+}