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