Blame src/FileCopyFtp.cc

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