|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 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 <errno.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include <math.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "NetAccess.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "LsCache.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "Speedometer.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define super FileAccess
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xmap_p<NetAccess::SiteData> NetAccess::site_data;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
resolver=0;
|
|
Packit |
8f70b4 |
idle_timer.SetResource("net:idle",0);
|
|
Packit |
8f70b4 |
timeout_timer.SetResource("net:timeout",0);
|
|
Packit |
8f70b4 |
max_persist_retries=0;
|
|
Packit |
8f70b4 |
persist_retries=0;
|
|
Packit |
8f70b4 |
socket_buffer=0;
|
|
Packit |
8f70b4 |
socket_maxseg=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
peer_curr=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
reconnect_interval=30; // retry with 30 second interval
|
|
Packit |
8f70b4 |
reconnect_interval_multiplier=1.2;
|
|
Packit |
8f70b4 |
reconnect_interval_max=300;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
rate_limit=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
connection_limit=0; // no limit.
|
|
Packit |
8f70b4 |
connection_takeover=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Reconfig(0);
|
|
Packit |
8f70b4 |
reconnect_interval_current=reconnect_interval;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
NetAccess::NetAccess()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
NetAccess::NetAccess(const NetAccess *o) : super(o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
if(o->peer)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
peer.set(o->peer);
|
|
Packit |
8f70b4 |
peer_curr=o->peer_curr;
|
|
Packit |
8f70b4 |
if(peer_curr>=peer.count())
|
|
Packit |
8f70b4 |
peer_curr=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
home_auto.set(o->home_auto);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
NetAccess::~NetAccess()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ClearPeer();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::Cleanup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(hostname==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo))
|
|
Packit |
8f70b4 |
fo->CleanupThis();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CleanupThis();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::CleanupThis()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!IsConnected() || mode!=CLOSED)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::Reconfig(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::Reconfig(name);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *c=hostname;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
reconnect_interval = ResMgr::Query("net:reconnect-interval-base",c);
|
|
Packit |
8f70b4 |
reconnect_interval_multiplier = ResMgr::Query("net:reconnect-interval-multiplier",c);
|
|
Packit |
8f70b4 |
if(reconnect_interval_multiplier<1)
|
|
Packit |
8f70b4 |
reconnect_interval_multiplier=1;
|
|
Packit |
8f70b4 |
reconnect_interval_max = ResMgr::Query("net:reconnect-interval-max",c);
|
|
Packit |
8f70b4 |
if(reconnect_interval_max
|
|
Packit |
8f70b4 |
reconnect_interval_max=reconnect_interval;
|
|
Packit |
8f70b4 |
max_retries = ResMgr::Query("net:max-retries",c);
|
|
Packit |
8f70b4 |
max_persist_retries = ResMgr::Query("net:persist-retries",c);
|
|
Packit |
8f70b4 |
socket_buffer = ResMgr::Query("net:socket-buffer",c);
|
|
Packit |
8f70b4 |
socket_maxseg = ResMgr::Query("net:socket-maxseg",c);
|
|
Packit |
8f70b4 |
connection_limit = ResMgr::Query("net:connection-limit",c);
|
|
Packit |
8f70b4 |
connection_takeover = ResMgr::QueryBool("net:connection-takeover",c);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(rate_limit)
|
|
Packit |
8f70b4 |
rate_limit->Reconfig(name,c);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *NetAccess::CheckHangup(const struct pollfd *pfd,int num)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef SO_ERROR
|
|
Packit |
8f70b4 |
int s_errno=0;
|
|
Packit |
8f70b4 |
errno=0;
|
|
Packit |
8f70b4 |
socklen_t len=sizeof(s_errno);
|
|
Packit |
8f70b4 |
getsockopt(pfd[i].fd,SOL_SOCKET,SO_ERROR,(char*)&s_errno,&len;;
|
|
Packit |
8f70b4 |
// Where does the error number go - to errno or to the pointer?
|
|
Packit |
8f70b4 |
// It seems that to errno, but if the pointer is NULL it dumps core.
|
|
Packit |
8f70b4 |
// (solaris 2.5)
|
|
Packit |
8f70b4 |
// It seems to be different on glibc 2.0 - check both errno and s_errno
|
|
Packit |
8f70b4 |
if((errno!=0 || s_errno!=0) && errno!=ENOTSOCK)
|
|
Packit |
8f70b4 |
return strerror(errno?errno:s_errno);
|
|
Packit |
8f70b4 |
#endif /* SO_ERROR */
|
|
Packit |
8f70b4 |
if(pfd[i].revents&POLLERR)
|
|
Packit |
8f70b4 |
return "POLLERR";
|
|
Packit |
8f70b4 |
} /* end for */
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int NetAccess::Poll(int fd,int ev,const char **err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct pollfd pfd;
|
|
Packit |
8f70b4 |
pfd.fd=fd;
|
|
Packit |
8f70b4 |
pfd.events=ev;
|
|
Packit |
8f70b4 |
pfd.revents=0;
|
|
Packit |
8f70b4 |
int res=poll(&pfd,1,0);
|
|
Packit |
8f70b4 |
if(res<1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
*err=CheckHangup(&pfd,1);
|
|
Packit |
8f70b4 |
if(*err)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
if(pfd.revents)
|
|
Packit |
8f70b4 |
timeout_timer.Reset();
|
|
Packit |
8f70b4 |
return pfd.revents;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::SayConnectingTo()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
assert(peer_curr
|
|
Packit |
8f70b4 |
const char *h=(proxy?proxy:hostname);
|
|
Packit |
8f70b4 |
LogNote(1,_("Connecting to %s%s (%s) port %u"),proxy?"proxy ":"",
|
|
Packit |
8f70b4 |
h,SocketNumericAddress(&peer[peer_curr]),SocketPort(&peer[peer_curr]));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::SetProxy(const char *px)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool was_proxied=(proxy!=0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
proxy.set(0);
|
|
Packit |
8f70b4 |
proxy_port.set(0);
|
|
Packit |
8f70b4 |
proxy_user.set(0);
|
|
Packit |
8f70b4 |
proxy_pass.set(0);
|
|
Packit |
8f70b4 |
proxy_proto.set(0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!px)
|
|
Packit |
8f70b4 |
px="";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ParsedURL url(px);
|
|
Packit |
8f70b4 |
if(!url.host || url.host[0]==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(was_proxied)
|
|
Packit |
8f70b4 |
ClearPeer();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
proxy.set(url.host);
|
|
Packit |
8f70b4 |
proxy_port.set(url.port);
|
|
Packit |
8f70b4 |
proxy_user.set(url.user);
|
|
Packit |
8f70b4 |
proxy_pass.set(url.pass);
|
|
Packit |
8f70b4 |
proxy_proto.set(url.proto);
|
|
Packit |
8f70b4 |
ClearPeer();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool NetAccess::NoProxy(const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// match hostname against no-proxy var.
|
|
Packit |
8f70b4 |
if(!hostname)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
const char *no_proxy_c=ResMgr::Query("net:no-proxy",0);
|
|
Packit |
8f70b4 |
if(!no_proxy_c)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
char *no_proxy=alloca_strdup(no_proxy_c);
|
|
Packit |
8f70b4 |
int h_len=strlen(hostname);
|
|
Packit |
8f70b4 |
for(char *p=strtok(no_proxy," ,"); p; p=strtok(0," ,"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int p_len=strlen(p);
|
|
Packit |
8f70b4 |
if(p_len>h_len || p_len==0)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(!strcasecmp(hostname+h_len-p_len,p))
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::HandleTimeout()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LogError(0,_("Timeout - reconnecting"));
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
timeout_timer.Reset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool NetAccess::CheckTimeout()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(timeout_timer.Stopped())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
HandleTimeout();
|
|
Packit |
8f70b4 |
return(true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return(false);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::ClearPeer()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
peer.unset();
|
|
Packit |
8f70b4 |
peer_curr=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::NextPeer()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
peer_curr++;
|
|
Packit |
8f70b4 |
if(peer_curr>=peer.count())
|
|
Packit |
8f70b4 |
peer_curr=0;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
DontSleep(); // try next address immediately
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::ResetLocationData()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
ClearPeer();
|
|
Packit |
8f70b4 |
super::ResetLocationData();
|
|
Packit |
8f70b4 |
timeout_timer.SetResource("net:timeout",hostname);
|
|
Packit |
8f70b4 |
idle_timer.SetResource("net:idle",hostname);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::Open(const char *fn,int mode,off_t offs)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
timeout_timer.Reset();
|
|
Packit |
8f70b4 |
super::Open(fn,mode,offs);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int NetAccess::Resolve(const char *defp,const char *ser,const char *pr)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!resolver)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
peer.unset();
|
|
Packit |
8f70b4 |
if(proxy)
|
|
Packit |
8f70b4 |
resolver=new Resolver(proxy,proxy_port,defp);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
resolver=new Resolver(hostname,portname,defp,ser,pr);
|
|
Packit |
8f70b4 |
if(!resolver)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
resolver->Roll();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!resolver->Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(resolver->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(LOOKUP_ERROR,resolver->ErrorMsg());
|
|
Packit |
8f70b4 |
return(MOVED);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
peer.set(resolver->Result());
|
|
Packit |
8f70b4 |
if(peer_curr>=peer.count())
|
|
Packit |
8f70b4 |
peer_curr=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
resolver=0;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool NetAccess::ReconnectAllowed()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(max_retries>0 && retries>=max_retries)
|
|
Packit |
8f70b4 |
return true; // it will fault later - no need to wait.
|
|
Packit |
8f70b4 |
int connection_limit=GetConnectionLimit();
|
|
Packit |
8f70b4 |
if(connection_limit>0 && connection_limit<=CountConnections())
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(reconnect_timer.Stopped())
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *NetAccess::DelayingMessage()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int connection_limit=GetConnectionLimit();
|
|
Packit |
8f70b4 |
if(connection_limit>0 && connection_limit<=CountConnections())
|
|
Packit |
8f70b4 |
return _("Connection limit reached");
|
|
Packit |
8f70b4 |
long remains=reconnect_timer.TimeLeft();
|
|
Packit |
8f70b4 |
if(remains<=0)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
current->TimeoutS(1);
|
|
Packit |
8f70b4 |
if(last_disconnect_cause && reconnect_timer.TimePassed()<5)
|
|
Packit |
8f70b4 |
return last_disconnect_cause;
|
|
Packit |
8f70b4 |
return xstring::format("%s: %ld",_("Delaying before reconnect"),remains);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool NetAccess::NextTry()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!CheckRetries())
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(retries==0)
|
|
Packit |
8f70b4 |
reconnect_interval_current=reconnect_interval;
|
|
Packit |
8f70b4 |
else if(reconnect_interval_multiplier>1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
reconnect_interval_current*=reconnect_interval_multiplier;
|
|
Packit |
8f70b4 |
if(reconnect_interval_current>reconnect_interval_max)
|
|
Packit |
8f70b4 |
reconnect_interval_current=reconnect_interval_max;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
retries++;
|
|
Packit |
8f70b4 |
LogNote(10,"attempt number %d (max_retries=%d)",retries,max_retries);
|
|
Packit |
8f70b4 |
return CheckRetries();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool NetAccess::CheckRetries()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(max_retries>0 && retries>max_retries)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!IsConnected() && last_disconnect_cause)
|
|
Packit |
8f70b4 |
Fatal(xstring::cat(_("max-retries exceeded")," (",last_disconnect_cause.get(),")",NULL));
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
Fatal(_("max-retries exceeded"));
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
reconnect_timer.Set(reconnect_interval_current);
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void NetAccess::TrySuccess()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
retries=0;
|
|
Packit |
8f70b4 |
persist_retries=0;
|
|
Packit |
8f70b4 |
reconnect_interval_current=reconnect_interval;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::Close()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode!=CLOSED)
|
|
Packit |
8f70b4 |
idle_timer.Reset();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
TrySuccess();
|
|
Packit |
8f70b4 |
resolver=0;
|
|
Packit |
8f70b4 |
super::Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int NetAccess::CountConnections()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int count=0;
|
|
Packit |
8f70b4 |
for(FileAccess *o=FirstSameSite(); o!=0; o=NextSameSite(o))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(o->IsConnected())
|
|
Packit |
8f70b4 |
count++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return count;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NetAccess::PropagateHomeAuto()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!home_auto)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NetAccess *o=(NetAccess*)fo; // we are sure it is NetAccess.
|
|
Packit |
8f70b4 |
if(!o->home_auto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
o->home_auto.set(home_auto);
|
|
Packit |
8f70b4 |
if(!o->home)
|
|
Packit |
8f70b4 |
o->set_home(home_auto);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *NetAccess::FindHomeAuto()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NetAccess *o=(NetAccess*)fo; // we are sure it is NetAccess.
|
|
Packit |
8f70b4 |
if(o->home_auto)
|
|
Packit |
8f70b4 |
return o->home_auto;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// GenericParseListInfo implementation
|
|
Packit |
8f70b4 |
int GenericParseListInfo::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#define need_size (need&FileInfo::SIZE)
|
|
Packit |
8f70b4 |
#define need_time (need&FileInfo::DATE)
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileInfo *file;
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
int old_mode=mode;
|
|
Packit |
8f70b4 |
Ref<FileSet> set;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
do_again:
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(redir_resolution) {
|
|
Packit |
8f70b4 |
if(redir_session && redir_session->OpenMode()==FA::ARRAY_INFO) {
|
|
Packit |
8f70b4 |
res=redir_session->Done();
|
|
Packit |
8f70b4 |
if(res==FA::DO_AGAIN || res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
redir_session->Close();
|
|
Packit |
8f70b4 |
redir_fs->rewind();
|
|
Packit |
8f70b4 |
FileInfo *fi=redir_fs->curr();
|
|
Packit |
8f70b4 |
if(ResolveRedirect(fi))
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
result->curr()->MergeInfo(*fi,~0U);
|
|
Packit |
8f70b4 |
result->next();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
redir_count=0;
|
|
Packit |
8f70b4 |
for(FileInfo *fi=result->curr(); fi; fi=result->next()) {
|
|
Packit |
8f70b4 |
if(ResolveRedirect(fi))
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess::cache->UpdateFileSet(session,"",FA::MP_LIST,result);
|
|
Packit |
8f70b4 |
FileAccess::cache->UpdateFileSet(session,"",FA::LONG_LIST,result);
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(session->OpenMode()==FA::ARRAY_INFO)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
res=session->Done();
|
|
Packit |
8f70b4 |
if(res==FA::DO_AGAIN)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
// start redirection resolution.
|
|
Packit |
8f70b4 |
redir_resolution=true;
|
|
Packit |
8f70b4 |
result->rewind();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
goto do_again;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ubuf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *cache_buffer=0;
|
|
Packit |
8f70b4 |
int cache_buffer_size=0;
|
|
Packit |
8f70b4 |
const FileSet *cache_fset=0;
|
|
Packit |
8f70b4 |
int err;
|
|
Packit |
8f70b4 |
if(use_cache && FileAccess::cache->Find(session,"",mode,&err,
|
|
Packit |
8f70b4 |
&cache_buffer,&cache_buffer_size,&cache_fset))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==FA::MP_LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode=FA::LONG_LIST;
|
|
Packit |
8f70b4 |
goto do_again;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetErrorCached(cache_buffer);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(cache_fset) {
|
|
Packit |
8f70b4 |
Log::global->Write(11,"ListInfo: using cached file set\n");
|
|
Packit |
8f70b4 |
set=new FileSet(cache_fset);
|
|
Packit |
8f70b4 |
old_mode=mode;
|
|
Packit |
8f70b4 |
goto got_fileset;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ubuf=new IOBuffer(IOBuffer::GET);
|
|
Packit |
8f70b4 |
ubuf->Put(cache_buffer,cache_buffer_size);
|
|
Packit |
8f70b4 |
ubuf->PutEOF();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session->Open("",mode);
|
|
Packit |
8f70b4 |
session->UseCache(use_cache);
|
|
Packit |
8f70b4 |
ubuf=new IOBufferFileAccess(session);
|
|
Packit |
8f70b4 |
ubuf->SetSpeedometer(new Speedometer());
|
|
Packit |
8f70b4 |
if(FileAccess::cache->IsEnabled(session->GetHostName()))
|
|
Packit |
8f70b4 |
ubuf->Save(FileAccess::cache->SizeLimit());
|
|
Packit |
8f70b4 |
session->Roll();
|
|
Packit |
8f70b4 |
ubuf->Roll();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(ubuf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ubuf->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileAccess::cache->Add(session,"",mode,session->GetErrorCode(),ubuf);
|
|
Packit |
8f70b4 |
if(mode==FA::MP_LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode=FA::LONG_LIST;
|
|
Packit |
8f70b4 |
ubuf=0;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
goto do_again;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetError(ubuf->ErrorText());
|
|
Packit |
8f70b4 |
ubuf=0;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ubuf->Eof())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// now we have all the index in ubuf; parse it.
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int len;
|
|
Packit |
8f70b4 |
ubuf->Get(&b,&len;;
|
|
Packit |
8f70b4 |
old_mode=mode;
|
|
Packit |
8f70b4 |
set=Parse(b,len);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// cache the list and the set.
|
|
Packit |
8f70b4 |
FileAccess::cache->Add(session,"",old_mode,FA::OK,ubuf,set);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
got_fileset:
|
|
Packit |
8f70b4 |
if(set)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool need_resort=false;
|
|
Packit |
8f70b4 |
set->rewind();
|
|
Packit |
8f70b4 |
for(file=set->curr(); file!=0; file=set->next())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// tilde is special.
|
|
Packit |
8f70b4 |
if(file->name[0]=='~')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file->name.set_substr(0,0,"./");
|
|
Packit |
8f70b4 |
need_resort=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(need_resort && !result)
|
|
Packit |
8f70b4 |
result=new FileSet; // Merge will sort the names
|
|
Packit |
8f70b4 |
if(result)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
result->Merge(set);
|
|
Packit |
8f70b4 |
set=0; // free it now.
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
result=set.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ubuf=0;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// try another mode? Parse() can set mode to indicate it wants to try it.
|
|
Packit |
8f70b4 |
if(mode!=old_mode)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!result)
|
|
Packit |
8f70b4 |
result=new FileSet;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(exclude)
|
|
Packit |
8f70b4 |
result->Exclude(exclude_prefix,exclude,excluded.get_non_const());
|
|
Packit |
8f70b4 |
result->rewind();
|
|
Packit |
8f70b4 |
for(file=result->curr(); file!=0; file=result->next())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file->need=0;
|
|
Packit |
8f70b4 |
if(need_size && !file->Has(file->SIZE))
|
|
Packit |
8f70b4 |
file->Need(file->SIZE);
|
|
Packit |
8f70b4 |
if(need_time && (!file->Has(file->DATE)
|
|
Packit |
8f70b4 |
|| (file->date.ts_prec>0 && can_get_prec_time)))
|
|
Packit |
8f70b4 |
file->Need(file->DATE);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(file->defined & file->TYPE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(file->filetype==file->SYMLINK && follow_symlinks)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file->filetype=file->UNKNOWN;
|
|
Packit |
8f70b4 |
file->defined &= ~(file->SIZE|file->SYMLINK_DEF|file->MODE|file->DATE|file->TYPE);
|
|
Packit |
8f70b4 |
file->Need(file->SIZE|file->DATE);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(file->filetype==file->SYMLINK)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// don't need these for symlinks
|
|
Packit |
8f70b4 |
file->NoNeed(file->SIZE|file->DATE);
|
|
Packit |
8f70b4 |
// but need the link target
|
|
Packit |
8f70b4 |
if(!file->Has(file->SYMLINK_DEF))
|
|
Packit |
8f70b4 |
file->Need(file->SYMLINK_DEF);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(file->filetype==file->DIRECTORY)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!get_time_for_dirs)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
// don't need size for directories
|
|
Packit |
8f70b4 |
file->NoNeed(file->SIZE);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
session->GetInfoArray(result.get_non_const());
|
|
Packit |
8f70b4 |
session->Roll();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool GenericParseListInfo::ResolveRedirect(const FileInfo *fi)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(fi->filetype!=fi->REDIRECT || redir_count>=max_redir)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
redir_count++;
|
|
Packit |
8f70b4 |
Log::global->Format(9,"ListInfo: resolving redirection %s -> %s\n",fi->name.get(),fi->GetRedirect());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Ref<FileInfo> redir_fi(new FileInfo());
|
|
Packit |
8f70b4 |
redir_fi->Need(fi->need);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring loc(fi->GetRedirect());
|
|
Packit |
8f70b4 |
ParsedURL u(loc,true);
|
|
Packit |
8f70b4 |
if(!u.proto) {
|
|
Packit |
8f70b4 |
// relative URI
|
|
Packit |
8f70b4 |
redir_session=session->Clone();
|
|
Packit |
8f70b4 |
if(loc[0]=='/' || fi->uri) {
|
|
Packit |
8f70b4 |
if(loc[0]!='/') {
|
|
Packit |
8f70b4 |
const char *slash=strrchr(fi->uri,'/');
|
|
Packit |
8f70b4 |
if(slash)
|
|
Packit |
8f70b4 |
loc.prepend(fi->uri,slash+1-fi->uri);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
redir_fi->uri.set(loc);
|
|
Packit |
8f70b4 |
redir_fi->name.set(loc);
|
|
Packit |
8f70b4 |
redir_fi->name.url_decode();
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
loc.url_decode();
|
|
Packit |
8f70b4 |
const char *slash=strrchr(fi->name,'/');
|
|
Packit |
8f70b4 |
if(slash)
|
|
Packit |
8f70b4 |
redir_fi->name.nset(fi->name,slash+1-fi->name);
|
|
Packit |
8f70b4 |
redir_fi->name.append(loc);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
} else { // u.proto
|
|
Packit |
8f70b4 |
// absolute URL
|
|
Packit |
8f70b4 |
redir_session=FileAccess::New(&u);
|
|
Packit |
8f70b4 |
redir_fi->name.set(u.path?u.path.get():"/");
|
|
Packit |
8f70b4 |
redir_fi->uri.set(url::path_ptr(u.orig_url));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!redir_fs)
|
|
Packit |
8f70b4 |
redir_fs=new FileSet();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
redir_fs->Empty();
|
|
Packit |
8f70b4 |
redir_fs->Add(redir_fi.borrow());
|
|
Packit |
8f70b4 |
redir_session->GetInfoArray(redir_fs.get_non_const());
|
|
Packit |
8f70b4 |
redir_session->Roll();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
GenericParseListInfo::GenericParseListInfo(FileAccess *s,const char *p)
|
|
Packit |
8f70b4 |
: ListInfo(s,p), redir_resolution(false), redir_count(0),
|
|
Packit |
8f70b4 |
max_redir(ResMgr::Query("xfer:max-redirections",0))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get_time_for_dirs=true;
|
|
Packit |
8f70b4 |
can_get_prec_time=true;
|
|
Packit |
8f70b4 |
mode=FA::MP_LIST;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *GenericParseListInfo::Status()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ubuf && !ubuf->Eof() && session->IsOpen())
|
|
Packit |
8f70b4 |
return xstring::format("%s (%lld) %s[%s]",_("Getting directory contents"),
|
|
Packit |
8f70b4 |
(long long)session->GetPos(),
|
|
Packit |
8f70b4 |
ubuf->GetRateStrS(),session->CurrentStatus());
|
|
Packit |
8f70b4 |
if(session->OpenMode()==FA::ARRAY_INFO)
|
|
Packit |
8f70b4 |
return xstring::format("%s (%d%%) [%s]",_("Getting files information"),
|
|
Packit |
8f70b4 |
session->InfoArrayPercentDone(),
|
|
Packit |
8f70b4 |
session->CurrentStatus());
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CDECL void lftp_network_cleanup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NetAccess::ClassCleanup();
|
|
Packit |
8f70b4 |
RateLimit::ClassCleanup();
|
|
Packit |
8f70b4 |
}
|