// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: ftp.cc,v 1.5 1999/03/15 19:51:27 jgg Exp $
+// $Id: ftp.cc,v 1.15 1999/09/05 05:41:41 jgg Exp $
/* ######################################################################
HTTP Aquire Method - This is the FTP aquire method for APT.
at all. Commands are sent syncronously with the FTP server (as the
rfc recommends, but it is not really necessary..) and no tricks are
done to speed things along.
-
+
+ RFC 2428 describes the IPv6 FTP behavior
+
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#include <arpa/inet.h>
#include <netdb.h>
+#include "rfc2553emu.h"
+#include "connect.h"
#include "ftp.h"
-
-
/*}}}*/
unsigned long TimeOut = 120;
// ---------------------------------------------------------------------
/* Connect to the server using a non-blocking connection and perform a
login. */
-string LastHost;
-in_addr LastHostA;
bool FTPConn::Open(pkgAcqMethod *Owner)
{
// Use the already open connection if possible.
Proxy = getenv("ftp_proxy");
// Determine what host and port to use based on the proxy settings
- int Port = 21;
+ int Port = 0;
string Host;
if (Proxy.empty() == true)
{
Port = Proxy.Port;
Host = Proxy.Host;
}
-
- /* We used a cached address record.. Yes this is against the spec but
- the way we have setup our rotating dns suggests that this is more
- sensible */
- if (LastHost != Host)
- {
- Owner->Status("Connecting to %s",Host.c_str());
-
- // Lookup the host
- hostent *Addr = gethostbyname(Host.c_str());
- if (Addr == 0 || Addr->h_addr_list[0] == 0)
- return _error->Error("Could not resolve '%s'",Host.c_str());
- LastHost = Host;
- LastHostA = *(in_addr *)(Addr->h_addr_list[0]);
- }
-
- Owner->Status("Connecting to %s (%s)",Host.c_str(),inet_ntoa(LastHostA));
-
- // Get a socket
- if ((ServerFd = socket(AF_INET,SOCK_STREAM,0)) < 0)
- return _error->Errno("socket","Could not create a socket");
-
- // Connect to the server
- struct sockaddr_in server;
- server.sin_family = AF_INET;
- server.sin_port = htons(Port);
- server.sin_addr = LastHostA;
- SetNonBlock(ServerFd,true);
- if (connect(ServerFd,(sockaddr *)&server,sizeof(server)) < 0 &&
- errno != EINPROGRESS)
- return _error->Errno("socket","Could not create a socket");
- Peer = server;
-
- /* This implements a timeout for connect by opening the connection
- nonblocking */
- if (WaitFd(ServerFd,true,TimeOut) == false)
- return _error->Error("Could not connect, connection timed out");
- unsigned int Err;
- unsigned int Len = sizeof(Err);
- if (getsockopt(ServerFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0)
- return _error->Errno("getsockopt","Failed");
- if (Err != 0)
- return _error->Error("Could not connect.");
+ // Connect to the remote server
+ if (Connect(Host,Port,"ftp",21,ServerFd,TimeOut,Owner) == false)
+ return false;
+ socklen_t Len = sizeof(Peer);
+ if (getpeername(ServerFd,(sockaddr *)&Peer,&Len) != 0)
+ return _error->Errno("getpeername","Unable to determine the peer name");
+
Owner->Status("Logging in");
return Login();
}
/* This performs a very simple buffered read. */
bool FTPConn::ReadLine(string &Text)
{
+ if (ServerFd == -1)
+ return false;
+
// Suck in a line
while (Len < sizeof(Buffer))
{
}
// Suck it back
- int Res = read(ServerFd,Buffer,sizeof(Buffer) - Len);
+ int Res = read(ServerFd,Buffer + Len,sizeof(Buffer) - Len);
if (Res <= 0)
{
Close();
return _error->Errno("socket","Could not create a socket");
/* This implements a timeout for connect by opening the connection
- nonblocking */
+ nonblocking */
if (WaitFd(ServerFd,true,TimeOut) == false)
return _error->Error("Could not connect data socket, connection timed out");
unsigned int Err;
{
// Wait for some data..
if (WaitFd(DataFd,false,TimeOut) == false)
- return _error->Error("Data socket connect timed out");
-
+ {
+ Close();
+ return _error->Error("Data socket timed out");
+ }
+
// Read the data..
int Res = read(DataFd,Buffer,sizeof(Buffer));
if (Res == 0)
MD5.Add(Buffer,Res);
if (To.Write(Buffer,Res) == false)
+ {
+ Close();
return false;
+ }
}
// All done
// Could not connect is a transient error..
if (Server->Open(this) == false)
{
+ Server->Close();
Fail(true);
return true;
}
bool Missing;
if (Server->Get(File,Fd,Res.ResumePoint,MD5,Missing) == false)
{
+ Fd.Close();
+
+ // Timestamp
+ struct utimbuf UBuf;
+ time(&UBuf.actime);
+ UBuf.actime = FailTime;
+ UBuf.modtime = FailTime;
+ utime(FailFile.c_str(),&UBuf);
+
// If the file is missing we hard fail otherwise transient fail
if (Missing == true)
return false;
}
/*}}}*/
-int main()
+int main(int argc,const char *argv[])
{
+ /* See if we should be come the http client - we do this for http
+ proxy urls */
+ if (getenv("ftp_proxy") != 0)
+ {
+ URI Proxy = string(getenv("ftp_proxy"));
+ if (Proxy.Access == "http")
+ {
+ // Copy over the environment setting
+ char S[300];
+ snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy"));
+ putenv(S);
+
+ // Run the http method
+ string Path = flNotFile(argv[0]) + "/http";
+ execl(Path.c_str(),Path.c_str(),0);
+ cerr << "Unable to invoke " << Path << endl;
+ exit(100);
+ }
+ }
+
FtpMethod Mth;
return Mth.Run();