Blame src/FileCopyFtp.cc

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
Packit 8f70b4
#include "FileCopyFtp.h"
Packit 8f70b4
#include "log.h"
Packit 8f70b4
Packit 8f70b4
#define super FileCopy
Packit 8f70b4
Packit 8f70b4
#if !USE_SSL
Packit 8f70b4
#define protect false
Packit 8f70b4
#define passive_ssl_connect true
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#define ftp_src get->GetSession().Cast<Ftp>()
Packit 8f70b4
#define ftp_dst put->GetSession().Cast<Ftp>()
Packit 8f70b4
Packit 8f70b4
void FileCopyFtp::Close()
Packit 8f70b4
{
Packit 8f70b4
   ftp_src->Close();
Packit 8f70b4
   ftp_dst->Close();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int FileCopyFtp::Do()
Packit 8f70b4
{
Packit 8f70b4
   int src_res,dst_res;
Packit 8f70b4
   int m=super::Do();
Packit 8f70b4
Packit 8f70b4
   if(disable_fxp || Error() || !put || !get)
Packit 8f70b4
      return m;
Packit 8f70b4
Packit 8f70b4
   if(state==PUT_WAIT && put->GetSeekPos()!=FILE_END)
Packit 8f70b4
   {
Packit 8f70b4
      if(get->GetSize()>=0 && put->GetSeekPos()>=get->GetSize())
Packit 8f70b4
	 return m;
Packit 8f70b4
      if(ftp_dst->IsClosed())
Packit 8f70b4
      {
Packit 8f70b4
	 put->OpenSession();
Packit 8f70b4
	 ftp_dst->SetCopyMode(Ftp::COPY_DEST,!passive_source,protect,
Packit 8f70b4
	       passive_source^passive_ssl_connect,dst_retries,dst_try_time);
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(state!=DO_COPY || put->GetSeekPos()==FILE_END || get->Eof())
Packit 8f70b4
      return m;
Packit 8f70b4
Packit 8f70b4
   // FileCopy can suspend peers.
Packit 8f70b4
   get->Resume();
Packit 8f70b4
   put->Resume();
Packit 8f70b4
Packit 8f70b4
   if(ftp_src->IsClosed())
Packit 8f70b4
   {
Packit 8f70b4
      get->OpenSession();
Packit 8f70b4
      ftp_src->SetCopyMode(Ftp::COPY_SOURCE,passive_source,protect,
Packit 8f70b4
	    !(passive_source^passive_ssl_connect),src_retries,src_try_time);
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   if(ftp_dst->IsClosed())
Packit 8f70b4
   {
Packit 8f70b4
      put->OpenSession();
Packit 8f70b4
      ftp_dst->SetCopyMode(Ftp::COPY_DEST,!passive_source,protect,
Packit 8f70b4
	    passive_source^passive_ssl_connect,dst_retries,dst_try_time);
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   // check for errors
Packit 8f70b4
   if(ftp_src->CopyFailed() || ftp_dst->CopyFailed())
Packit 8f70b4
   {
Packit 8f70b4
      if(ftp_src->RestartFailed() || ftp_dst->RestartFailed())
Packit 8f70b4
      {
Packit 8f70b4
	 get->CannotSeek(put->GetSize());
Packit 8f70b4
	 put->CannotSeek(put->GetSize());
Packit 8f70b4
      }
Packit 8f70b4
      else if(passive_source==orig_passive_source)
Packit 8f70b4
      {
Packit 8f70b4
	 passive_source=!passive_source;
Packit 8f70b4
	 Log::global->Write(0,_("**** FXP: trying to reverse ftp:fxp-passive-source\n"));
Packit 8f70b4
      }
Packit 8f70b4
#if USE_SSL
Packit 8f70b4
      else if(passive_ssl_connect==orig_passive_ssl_connect)
Packit 8f70b4
      {
Packit 8f70b4
	 passive_ssl_connect=!passive_ssl_connect;
Packit 8f70b4
	 passive_source=orig_passive_source;
Packit 8f70b4
	 Log::global->Write(0,_("**** FXP: trying to reverse ftp:fxp-passive-sscn\n"));
Packit 8f70b4
      }
Packit 8f70b4
      else if(protect
Packit 8f70b4
      && !ResMgr::QueryBool("ftp:ssl-force",ftp_src->GetHostName())
Packit 8f70b4
      && !ResMgr::QueryBool("ftp:ssl-force",ftp_dst->GetHostName()))
Packit 8f70b4
      {
Packit 8f70b4
	 passive_source=orig_passive_source;
Packit 8f70b4
	 protect=false;
Packit 8f70b4
	 Log::global->Write(0,_("**** FXP: trying to reverse ftp:ssl-protect-fxp\n"));
Packit 8f70b4
      }
Packit 8f70b4
#endif // USE_SSL
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 // both ways failed. Fall back to normal copying.
Packit 8f70b4
	 Log::global->Write(0,_("**** FXP: giving up, reverting to plain copy\n"));
Packit 8f70b4
	 Close();
Packit 8f70b4
	 disable_fxp=true;
Packit 8f70b4
	 get->SetFXP(false);
Packit 8f70b4
	 put->SetFXP(false);
Packit 8f70b4
Packit 8f70b4
	 if(ResMgr::QueryBool("ftp:fxp-force",ftp_src->GetHostName())
Packit 8f70b4
	 || ResMgr::QueryBool("ftp:fxp-force",ftp_dst->GetHostName()))
Packit 8f70b4
	 {
Packit 8f70b4
	    SetError(_("ftp:fxp-force is set but FXP is not available"));
Packit 8f70b4
	    return MOVED;
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 off_t pos=put->GetRealPos();
Packit 8f70b4
	 if(!get->CanSeek(pos) || !put->CanSeek(pos))
Packit 8f70b4
	    pos=0;
Packit 8f70b4
	 get->Seek(pos);
Packit 8f70b4
	 put->Seek(pos);
Packit 8f70b4
	 RateReset();
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      RateReset();
Packit 8f70b4
Packit 8f70b4
      src_retries=ftp_src->GetRetries();
Packit 8f70b4
      dst_retries=ftp_dst->GetRetries();
Packit 8f70b4
      src_try_time=ftp_src->GetTryTime();
Packit 8f70b4
      dst_try_time=ftp_dst->GetTryTime();
Packit 8f70b4
      Close();
Packit 8f70b4
      if(put->CanSeek())
Packit 8f70b4
      {
Packit 8f70b4
	 put->Seek(FILE_END);
Packit 8f70b4
	 get->Suspend();
Packit 8f70b4
	 put->Resume();
Packit 8f70b4
	 state=PUT_WAIT;
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
	 put->Seek(0);
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   src_res=ftp_src->Done();
Packit 8f70b4
   dst_res=ftp_dst->Done();
Packit 8f70b4
   if(src_res==FA::OK && dst_res==FA::OK)
Packit 8f70b4
   {
Packit 8f70b4
      Close();
Packit 8f70b4
      const long long size=GetSize();
Packit 8f70b4
      if(size>=0)
Packit 8f70b4
      {
Packit 8f70b4
	 get->SetPos(size);
Packit 8f70b4
	 put->SetPos(size);
Packit 8f70b4
      }
Packit 8f70b4
      get->PutEOF();
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   if(src_res!=FA::IN_PROGRESS && src_res!=FA::OK)
Packit 8f70b4
   {
Packit 8f70b4
      SetError(ftp_src->StrError(src_res));
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   if(dst_res!=FA::IN_PROGRESS && dst_res!=FA::OK)
Packit 8f70b4
   {
Packit 8f70b4
      SetError(ftp_dst->StrError(dst_res));
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   // exchange copy address
Packit 8f70b4
   if(ftp_dst->SetCopyAddress(ftp_src) || ftp_src->SetCopyAddress(ftp_dst))
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
Packit 8f70b4
   if(!ftp_dst->CopyStoreAllowed()
Packit 8f70b4
   && ftp_src->CopyIsReadyForStore() && ftp_dst->CopyIsReadyForStore())
Packit 8f70b4
   {
Packit 8f70b4
      ftp_dst->CopyAllowStore();
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
      RateReset();
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   // check for timeout when one session is done, and the other is stuck
Packit 8f70b4
   if(dst_res==FA::OK && src_res==FA::IN_PROGRESS)
Packit 8f70b4
      ftp_src->CopyCheckTimeout(ftp_dst);
Packit 8f70b4
   if(src_res==FA::OK && dst_res==FA::IN_PROGRESS)
Packit 8f70b4
      ftp_dst->CopyCheckTimeout(ftp_src);
Packit 8f70b4
Packit 8f70b4
   off_t add=ftp_dst->GetPos()-put->GetRealPos();
Packit 8f70b4
   if(add>0)
Packit 8f70b4
   {
Packit 8f70b4
      RateAdd(add);
Packit 8f70b4
      bytes_count+=add;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   off_t pos=ftp_dst->GetPos();
Packit 8f70b4
   get->SetPos(pos);
Packit 8f70b4
   put->SetPos(pos);
Packit 8f70b4
Packit 8f70b4
   return m;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void FileCopyFtp::Init()
Packit 8f70b4
{
Packit 8f70b4
   no_rest=false;
Packit 8f70b4
   orig_passive_source=passive_source=false;
Packit 8f70b4
   src_retries=dst_retries=0;
Packit 8f70b4
   src_try_time=dst_try_time=0;
Packit 8f70b4
   disable_fxp=false;
Packit 8f70b4
#if USE_SSL
Packit 8f70b4
   protect=false;
Packit 8f70b4
   orig_passive_ssl_connect=passive_ssl_connect=true;
Packit 8f70b4
#endif
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
// s,d must be FileCopyPeerFA, s->GetSession(),d->GetSession() must be Ftp.
Packit 8f70b4
FileCopyFtp::FileCopyFtp(FileCopyPeer *s,FileCopyPeer *d,bool c,bool rp)
Packit 8f70b4
   : super(s,d,c)
Packit 8f70b4
{
Packit 8f70b4
   Init();
Packit 8f70b4
   passive_source=rp;
Packit 8f70b4
Packit 8f70b4
   get->SetFXP(true);
Packit 8f70b4
   put->SetFXP(true);
Packit 8f70b4
Packit 8f70b4
   if(ftp_src->IsPassive() && !ftp_dst->IsPassive())
Packit 8f70b4
      passive_source=true;
Packit 8f70b4
   else if(!ftp_src->IsPassive() && ftp_dst->IsPassive())
Packit 8f70b4
      passive_source=false;
Packit 8f70b4
   orig_passive_source=passive_source;
Packit 8f70b4
Packit 8f70b4
#if USE_SSL
Packit 8f70b4
   if(ResMgr::QueryBool("ftp:ssl-protect-fxp",ftp_src->GetHostName())
Packit 8f70b4
   || ResMgr::QueryBool("ftp:ssl-protect-fxp",ftp_dst->GetHostName()))
Packit 8f70b4
      protect=true;
Packit 8f70b4
   passive_ssl_connect=ResMgr::QueryBool("ftp:fxp-passive-sscn",0);
Packit 8f70b4
   orig_passive_ssl_connect=passive_ssl_connect;
Packit 8f70b4
#endif
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
FileCopy *FileCopyFtp::New(FileCopyPeer *s,FileCopyPeer *d,bool c)
Packit 8f70b4
{
Packit 8f70b4
   const FileAccessRef& s_s=s->GetSession();
Packit 8f70b4
   const FileAccessRef& d_s=d->GetSession();
Packit 8f70b4
   if(!s_s || !d_s)
Packit 8f70b4
      return 0;
Packit 8f70b4
   if((strcmp(s_s->GetProto(),"ftp") && strcmp(s_s->GetProto(),"ftps"))
Packit 8f70b4
   || (strcmp(d_s->GetProto(),"ftp") && strcmp(d_s->GetProto(),"ftps")))
Packit 8f70b4
      return 0;
Packit 8f70b4
   if(!ResMgr::QueryBool("ftp:use-fxp",s_s->GetHostName())
Packit 8f70b4
   || !ResMgr::QueryBool("ftp:use-fxp",d_s->GetHostName()))
Packit 8f70b4
      return 0;
Packit 8f70b4
   return new FileCopyFtp(s,d,c,ResMgr::QueryBool("ftp:fxp-passive-source",0));
Packit 8f70b4
}