// BamFtp_p.cpp (c) 2011 Derek Barnett
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
-// Last modified: 8 November 2011 (DB)
+// Last modified: 8 December 2011 (DB)
// ---------------------------------------------------------------------------
// Provides reading/writing of BAM files on FTP server
// ***************************************************************************
using namespace BamTools;
using namespace BamTools::Internal;
-#include <iostream> // debug
-
#include <cctype>
#include <cstdlib>
#include <sstream>
// constants
// -----------
-static const uint16_t FTP_PORT = 21;
-static const string FTP_PREFIX = "ftp://";
-static const size_t FTP_PREFIX_LENGTH = 6;
-static const string FTP_NEWLINE = "\r\n";
+static const uint16_t FTP_PORT = 21;
+static const string FTP_PREFIX = "ftp://";
+static const size_t FTP_PREFIX_LENGTH = 6;
+static const string FTP_NEWLINE = "\r\n";
+
static const string DEFAULT_USER = "anonymous";
static const string DEFAULT_PASS = "anonymous@";
+
static const string ABOR_CMD = "ABOR";
static const string USER_CMD = "USER";
static const string PASS_CMD = "PASS";
static const string REST_CMD = "REST";
static const string RETR_CMD = "RETR";
static const string TYPE_CMD = "TYPE";
-static const char COLON_CHAR = ':';
-static const char COMMA_CHAR = ',';
-static const char DOT_CHAR = '.';
-static const char MINUS_CHAR = '-';
-static const char SLASH_CHAR = '/';
-static const char SPACE_CHAR = ' ';
-static const char LEFT_PAREN_CHAR = '(';
-static const char RIGHT_PAREN_CHAR = ')';
+
+static const char CMD_SEPARATOR = ' ';
+static const char HOST_SEPARATOR = '/';
+static const char IP_SEPARATOR = '.';
+
+static const char MULTILINE_CONTINUE = '-';
+
+static const char PASV_REPLY_PREFIX = '(';
+static const char PASV_REPLY_SEPARATOR = ',';
+static const char PASV_REPLY_SUFFIX = ')';
// -----------------
// utility methods
string toLower(const string& s) {
string out;
const size_t sSize = s.size();
- out.reserve(sSize);
+ out.resize(sSize);
for ( size_t i = 0; i < sSize; ++i )
out[i] = tolower(s[i]);
return out;
// connect to FTP server
if ( !m_commandSocket->ConnectToHost(m_hostname, m_port, m_mode) ) {
- SetErrorString("BamFtp::ConnectCommandSocket", "could not connect to host");
+ SetErrorString("BamFtp::ConnectCommandSocket", "could not connect to host - ");
return false;
}
}
// send USER command
- string userCommand = USER_CMD + SPACE_CHAR + m_username + FTP_NEWLINE;
+ string userCommand = USER_CMD + CMD_SEPARATOR + m_username + FTP_NEWLINE;
if ( !SendCommand(userCommand, true) ) {
Close();
return false;
}
// send PASS command
- string passwordCommand = PASS_CMD + SPACE_CHAR + m_password + FTP_NEWLINE;
+ string passwordCommand = PASS_CMD + CMD_SEPARATOR + m_password + FTP_NEWLINE;
if ( !SendCommand(passwordCommand, true) ) {
Close();
return false;
}
// send TYPE command
- string typeCommand = TYPE_CMD + SPACE_CHAR + "I" + FTP_NEWLINE;
+ string typeCommand = TYPE_CMD + CMD_SEPARATOR + 'I' + FTP_NEWLINE;
if ( !SendCommand(typeCommand, true) ) {
Close();
return false;
}
// make sure we're starting with a fresh data channel
- if ( m_dataSocket->IsConnected() )
+ if ( m_dataSocket->IsConnected() )
m_dataSocket->DisconnectFromHost();
// send passive connection command
stringstream fpStream("");
fpStream << m_filePosition;
- string restartCommand = REST_CMD + SPACE_CHAR + fpStream.str() + FTP_NEWLINE;
+ string restartCommand = REST_CMD + CMD_SEPARATOR + fpStream.str() + FTP_NEWLINE;
if ( !SendCommand(restartCommand, true) ) {
// TODO: set error string
return false;
}
// main file retrieval request
- string retrieveCommand = RETR_CMD + SPACE_CHAR + m_filename + FTP_NEWLINE;
+ string retrieveCommand = RETR_CMD + CMD_SEPARATOR + m_filename + FTP_NEWLINE;
if ( !SendCommand(retrieveCommand, false) ) {
// TODO: set error string
return false;
m_dataSocket->DisconnectFromHost();
return false;
}
-
+
// make sure we have reply code 150 (all good)
if ( !startsWith(m_response, "150") ) {
// TODO: set error string
return false;
// find parentheses
- const size_t leftParenFound = m_response.find(LEFT_PAREN_CHAR);
- const size_t rightParenFound = m_response.find(RIGHT_PAREN_CHAR);
+ const size_t leftParenFound = m_response.find(PASV_REPLY_PREFIX);
+ const size_t rightParenFound = m_response.find(PASV_REPLY_SUFFIX);
if ( leftParenFound == string::npos || rightParenFound == string::npos )
return false;
const string hostAndPort(responseBegin+leftParenFound+1, responseBegin+rightParenFound);
// parse into string fields
- vector<string> fields = split(hostAndPort, COMMA_CHAR);
+ vector<string> fields = split(hostAndPort, PASV_REPLY_SEPARATOR);
if ( fields.size() != 6 )
return false;
// fetch passive connection IP
- m_dataHostname = fields[0] + DOT_CHAR +
- fields[1] + DOT_CHAR +
- fields[2] + DOT_CHAR +
+ m_dataHostname = fields[0] + IP_SEPARATOR +
+ fields[1] + IP_SEPARATOR +
+ fields[2] + IP_SEPARATOR +
fields[3];
// fetch passive connection port
return;
// find end of host name portion (first '/' hit after the prefix)
- const size_t firstSlashFound = tempUrl.find(SLASH_CHAR, FTP_PREFIX_LENGTH);
+ const size_t firstSlashFound = tempUrl.find(HOST_SEPARATOR, FTP_PREFIX_LENGTH);
if ( firstSlashFound == string::npos ) {
; // no slash found... no filename given along with host?
}
// read bytes from data socket
const int64_t socketBytesRead = ReadDataSocket(data+bytesReadSoFar, remainingBytes);
- if ( socketBytesRead < 0 )
+ if ( socketBytesRead < 0 ) // error
return -1;
+ else if ( socketBytesRead == 0 ) // EOF
+ return bytesReadSoFar;
bytesReadSoFar += socketBytesRead;
m_filePosition += socketBytesRead;
}
}
int64_t BamFtp::ReadCommandSocket(char* data, const unsigned int maxNumBytes) {
-
- // try to read 'remainingBytes' from socket
- const int64_t numBytesRead = m_commandSocket->Read(data, maxNumBytes);
- if ( numBytesRead < 0 )
- return -1;
- return numBytesRead;
+ return m_commandSocket->Read(data, maxNumBytes);
}
int64_t BamFtp::ReadDataSocket(char* data, const unsigned int maxNumBytes) {
-
- // try to read 'remainingBytes' from socket
- const int64_t numBytesRead = m_dataSocket->Read(data, maxNumBytes);
- if ( numBytesRead < 0 )
- return -1;
- return numBytesRead;
+ return m_dataSocket->Read(data, maxNumBytes);
}
bool BamFtp::ReceiveReply(void) {
isdigit(headerLine[0]) &&
isdigit(headerLine[1]) &&
isdigit(headerLine[2]) &&
- ( headerLine[3] != MINUS_CHAR )
+ ( headerLine[3] != MULTILINE_CONTINUE )
)
{
headerEnd = true;