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. The server normally accepts PASV with code 227. * Its response is a single line showing the IP address of the server and * the TCP port number where the server is accepting connections. */ 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; }
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 = ftpc_dequote(login->uname); session->pwd = ftpc_dequote(login->pwd); session->initrdir = ftpc_dequote(login->rdir); /* Is passive mode requested? */ FTPC_CLR_PASSIVE(session); if (login->pasv) { nvdbg("Setting passive mode\n"); 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; }
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); }
int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream) { 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(session->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> */ nvdbg("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(session->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; }
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)) { ndbg("Not connected\n"); 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) { ndbg("ftp_pasvmode() failed: %d\n", errno); goto errout_with_data; } /* Configure the data socket */ ftpc_sockgetsockname(&session->cmd, &addr); memcpy(&addr.sin_addr, addrport, 4); memcpy(&addr.sin_port, addrport+4, 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; }