diff options
Diffstat (limited to 'methods')
-rw-r--r-- | methods/connect.cc | 18 | ||||
-rw-r--r-- | methods/http.cc | 16 | ||||
-rw-r--r-- | methods/http.h | 6 | ||||
-rw-r--r-- | methods/http_main.cc | 15 | ||||
-rw-r--r-- | methods/https.cc | 28 | ||||
-rw-r--r-- | methods/makefile | 27 | ||||
-rw-r--r-- | methods/mirror.cc | 282 | ||||
-rw-r--r-- | methods/mirror.h | 51 |
8 files changed, 409 insertions, 34 deletions
diff --git a/methods/connect.cc b/methods/connect.cc index 8c2ac6d56..145001fb3 100644 --- a/methods/connect.cc +++ b/methods/connect.cc @@ -18,6 +18,7 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> +#include <sstream> // Internet stuff #include <netinet/in.h> @@ -67,12 +68,10 @@ static bool DoConnect(struct addrinfo *Addr,string Host, wrong this will get tacked onto the end of the error message */ if (LastHostAddr->ai_next != 0) { - char Name2[NI_MAXHOST + NI_MAXSERV + 10]; - snprintf(Name2,sizeof(Name2),_("[IP: %s %s]"),Name,Service); - Owner->SetFailExtraMsg(string(Name2)); - } - else - Owner->SetFailExtraMsg(""); + std::stringstream ss; + ioprintf(ss, _("[IP: %s %s]"),Name,Service); + Owner->SetIP(ss.str()); + } // Get a socket if ((Fd = socket(Addr->ai_family,Addr->ai_socktype, @@ -89,7 +88,7 @@ static bool DoConnect(struct addrinfo *Addr,string Host, /* This implements a timeout for connect by opening the connection nonblocking */ if (WaitFd(Fd,true,TimeOut) == false) { - Owner->SetFailExtraMsg("\nFailReason: Timeout"); + Owner->SetFailReason("Timeout"); return _error->Error(_("Could not connect to %s:%s (%s), " "connection timed out"),Host.c_str(),Service,Name); } @@ -104,7 +103,7 @@ static bool DoConnect(struct addrinfo *Addr,string Host, { errno = Err; if(errno == ECONNREFUSED) - Owner->SetFailExtraMsg("\nFailReason: ConnectionRefused"); + Owner->SetFailReason("ConnectionRefused"); return _error->Errno("connect",_("Could not connect to %s:%s (%s)."),Host.c_str(), Service,Name); } @@ -164,12 +163,13 @@ bool Connect(string Host,int Port,const char *Service,int DefPort,int &Fd, DefPort = 0; continue; } + Owner->SetFailReason("ResolveFailure"); return _error->Error(_("Could not resolve '%s'"),Host.c_str()); } if (Res == EAI_AGAIN) { - Owner->SetFailExtraMsg("\nFailReason: TmpResolveFailure"); + Owner->SetFailReason("TmpResolveFailure"); return _error->Error(_("Temporary failure resolving '%s'"), Host.c_str()); } diff --git a/methods/http.cc b/methods/http.cc index d4e231fbe..6aa4261ff 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -38,7 +38,6 @@ #include <stdio.h> #include <errno.h> #include <string.h> -#include <iostream> #include <apti18n.h> // Internet stuff @@ -715,7 +714,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) Req += string("Authorization: Basic ") + Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n"; - Req += "User-Agent: Debian APT-HTTP/1.3 ("VERSION")\r\n\r\n"; + Req += "User-Agent: Ubuntu APT-HTTP/1.3 ("VERSION")\r\n\r\n"; if (Debug == true) cerr << Req << endl; @@ -916,6 +915,9 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) failure */ if (Srv->Result < 200 || Srv->Result >= 300) { + char err[255]; + snprintf(err,sizeof(err)-1,"HttpError%i",Srv->Result); + SetFailReason(err); _error->Error("%u %s",Srv->Result,Srv->Code); if (Srv->HaveContent == true) return 4; @@ -991,7 +993,7 @@ void HttpMethod::SigTerm(int) depth. */ bool HttpMethod::Fetch(FetchItem *) { - if (Server == 0) + if (Server == 0) return true; // Queue the requests @@ -1236,13 +1238,5 @@ int HttpMethod::Loop() } /*}}}*/ -int main() -{ - setlocale(LC_ALL, ""); - - HttpMethod Mth; - - return Mth.Loop(); -} diff --git a/methods/http.h b/methods/http.h index 6753a9901..dec5cd80f 100644 --- a/methods/http.h +++ b/methods/http.h @@ -13,7 +13,7 @@ #define MAXLEN 360 -#include <iostream> + using std::cout; using std::endl; @@ -134,7 +134,6 @@ class HttpMethod : public pkgAcqMethod bool ServerDie(ServerState *Srv); int DealWithHeaders(FetchResult &Res,ServerState *Srv); - virtual bool Fetch(FetchItem *); virtual bool Configuration(string Message); // In the event of a fatal signal this file will be closed and timestamped. @@ -142,6 +141,9 @@ class HttpMethod : public pkgAcqMethod static int FailFd; static time_t FailTime; static void SigTerm(int); + + protected: + virtual bool Fetch(FetchItem *); public: friend class ServerState; diff --git a/methods/http_main.cc b/methods/http_main.cc new file mode 100644 index 000000000..2c46ab19d --- /dev/null +++ b/methods/http_main.cc @@ -0,0 +1,15 @@ +#include <apt-pkg/fileutl.h> +#include <apt-pkg/acquire-method.h> + +#include "connect.h" +#include "rfc2553emu.h" +#include "http.h" + + +int main() +{ + setlocale(LC_ALL, ""); + + HttpMethod Mth; + return Mth.Loop(); +} diff --git a/methods/https.cc b/methods/https.cc index d48ac97fb..e6717e63a 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -107,6 +107,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm) struct stat SBuf; struct curl_slist *headers=NULL; char curl_errorstr[CURL_ERROR_SIZE]; + long curl_responsecode; // TODO: // - http::Timeout @@ -159,8 +160,11 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // set time values - curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); - curl_easy_setopt(curl, CURLOPT_TIMEVALUE, Itm->LastModified); + if(Itm->LastModified > 0) + { + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, Itm->LastModified); + } // speed limit int dlLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024; @@ -178,8 +182,14 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errorstr); // In this case we send an if-range query with a range header - if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) - curl_easy_setopt(curl, CURLOPT_RESUME_FROM, (long)SBuf.st_size); + if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) + { + char Buf[1000]; + sprintf(Buf,"Range: bytes=%li-\r\nIf-Range: %s\r\n", + (long)SBuf.st_size - 1, + TimeRFC1123(SBuf.st_mtime).c_str()); + headers = curl_slist_append(headers, Buf); + } // go for it - if the file exists, append on it File = new FileFd(Itm->DestFile, FileFd::WriteAny); @@ -190,14 +200,17 @@ bool HttpsMethod::Fetch(FetchItem *Itm) // get it! CURLcode success = curl_easy_perform(curl); - + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &curl_responsecode); // cleanup - if(success != 0) { + if(success != 0) + { + unlink(File->Name().c_str()); _error->Error(curl_errorstr); Fail(); return true; } + File->Close(); if (Res.Size == 0) Res.Size = File->Size(); @@ -210,7 +223,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm) Res.Filename = File->Name(); Res.LastModified = Buf.st_mtime; Res.IMSHit = false; - if (Itm->LastModified != 0 && Buf.st_mtime >= Itm->LastModified) + if (curl_responsecode == 304) { Res.IMSHit = true; Res.LastModified = Itm->LastModified; @@ -227,7 +240,6 @@ bool HttpsMethod::Fetch(FetchItem *Itm) URIDone(Res); // cleanup - File->Close(); Res.Size = 0; delete File; curl_slist_free_all(headers); diff --git a/methods/makefile b/methods/makefile index 16900116a..b7c595754 100644 --- a/methods/makefile +++ b/methods/makefile @@ -49,7 +49,14 @@ include $(PROGRAM_H) PROGRAM=http SLIBS = -lapt-pkg $(SOCKETLIBS) LIB_MAKES = apt-pkg/makefile -SOURCE = http.cc rfc2553emu.cc connect.cc +SOURCE = http.cc http_main.cc rfc2553emu.cc connect.cc +include $(PROGRAM_H) + +# The https method +PROGRAM=https +SLIBS = -lapt-pkg -lcurl +LIB_MAKES = apt-pkg/makefile +SOURCE = https.cc include $(PROGRAM_H) # The https method @@ -80,9 +87,16 @@ LIB_MAKES = apt-pkg/makefile SOURCE = rsh.cc include $(PROGRAM_H) -# SSH and vzip2 method symlink -binary: $(BIN)/ssh $(BIN)/bzip2 -veryclean: clean-$(BIN)/ssh clean-$(BIN)/bzip2 +# The mirror method +PROGRAM=mirror +SLIBS = -lapt-pkg $(SOCKETLIBS) +LIB_MAKES = apt-pkg/makefile +SOURCE = mirror.cc http.cc rfc2553emu.cc connect.cc +include $(PROGRAM_H) + +# SSH and bzip2,lzma method symlinks +binary: $(BIN)/ssh $(BIN)/bzip2 $(BIN)/lzma +veryclean: clean-$(BIN)/ssh clean-$(BIN)/bzip2 clean-$(BIN)/lzma $(BIN)/ssh: echo "Installing ssh method link" ln -fs rsh $(BIN)/ssh @@ -92,5 +106,10 @@ clean-$(BIN)/ssh: $(BIN)/bzip2: echo "Installing bzip2 method link" ln -fs gzip $(BIN)/bzip2 +$(BIN)/lzma: + echo "Installing lzma method link" + ln -fs gzip $(BIN)/lzma clean-$(BIN)/bzip2: -rm $(BIN)/bzip2 +clean-$(BIN)/lzma: + -rm $(BIN)/lzma diff --git a/methods/mirror.cc b/methods/mirror.cc new file mode 100644 index 000000000..9fe64fd70 --- /dev/null +++ b/methods/mirror.cc @@ -0,0 +1,282 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: mirror.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ +/* ###################################################################### + + Mirror Aquire Method - This is the Mirror aquire method for APT. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include <apt-pkg/fileutl.h> +#include <apt-pkg/acquire-method.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/acquire.h> +#include <apt-pkg/error.h> +#include <apt-pkg/hashes.h> +#include <apt-pkg/sourcelist.h> + +#include <fstream> +#include <iostream> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> + +using namespace std; + +#include "mirror.h" +#include "http.h" +#include "apti18n.h" + /*}}}*/ + +/* Done: + * - works with http (only!) + * - always picks the first mirror from the list + * - call out to problem reporting script + * - supports "deb mirror://host/path/to/mirror-list/// dist component" + * - uses pkgAcqMethod::FailReason() to have a string representation + * of the failure that is also send to LP + * + * TODO: + * - deal with runing as non-root because we can't write to the lists + dir then -> use the cached mirror file + * - better method to download than having a pkgAcquire interface here + * and better error handling there! + * - support more than http + * - testing :) + */ + +MirrorMethod::MirrorMethod() + : HttpMethod(), HasMirrorFile(false) +{ +}; + +// HttpMethod::Configuration - Handle a configuration message /*{{{*/ +// --------------------------------------------------------------------- +/* We stash the desired pipeline depth */ +bool MirrorMethod::Configuration(string Message) +{ + if (pkgAcqMethod::Configuration(Message) == false) + return false; + Debug = _config->FindB("Debug::Acquire::mirror",false); + + return true; +} + /*}}}*/ + +// clean the mirrors dir based on ttl information +bool MirrorMethod::Clean(string Dir) +{ + vector<metaIndex *>::const_iterator I; + + if(Debug) + clog << "MirrorMethod::Clean(): " << Dir << endl; + + // read sources.list + pkgSourceList list; + list.ReadMainList(); + + DIR *D = opendir(Dir.c_str()); + if (D == 0) + return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); + + string StartDir = SafeGetCWD(); + if (chdir(Dir.c_str()) != 0) + { + closedir(D); + return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str()); + } + + for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) + { + // Skip some files.. + if (strcmp(Dir->d_name,"lock") == 0 || + strcmp(Dir->d_name,"partial") == 0 || + strcmp(Dir->d_name,".") == 0 || + strcmp(Dir->d_name,"..") == 0) + continue; + + // see if we have that uri + for(I=list.begin(); I != list.end(); I++) + { + string uri = (*I)->GetURI(); + if(uri.substr(0,strlen("mirror://")) != string("mirror://")) + continue; + string BaseUri = uri.substr(0,uri.size()-1); + if (URItoFileName(BaseUri) == Dir->d_name) + break; + } + // nothing found, nuke it + if (I == list.end()) + unlink(Dir->d_name); + }; + + chdir(StartDir.c_str()); + closedir(D); + return true; +} + + +bool MirrorMethod::GetMirrorFile(string mirror_uri_str) +{ + /* + - a mirror_uri_str looks like this: + mirror://people.ubuntu.com/~mvo/apt/mirror/mirrors/dists/feisty/Release.gpg + + - the matching source.list entry + deb mirror://people.ubuntu.com/~mvo/apt/mirror/mirrors feisty main + + - we actually want to go after: + http://people.ubuntu.com/~mvo/apt/mirror/mirrors + + And we need to save the BaseUri for later: + - mirror://people.ubuntu.com/~mvo/apt/mirror/mirrors + + FIXME: what if we have two similar prefixes? + mirror://people.ubuntu.com/~mvo/mirror + mirror://people.ubuntu.com/~mvo/mirror2 + then mirror_uri_str looks like: + mirror://people.ubuntu.com/~mvo/apt/mirror/dists/feisty/Release.gpg + mirror://people.ubuntu.com/~mvo/apt/mirror2/dists/feisty/Release.gpg + we search sources.list and find: + mirror://people.ubuntu.com/~mvo/apt/mirror + in both cases! So we need to apply some domain knowledge here :( and + check for /dists/ or /Release.gpg as suffixes + */ + if(Debug) + std::cerr << "GetMirrorFile: " << mirror_uri_str << std::endl; + + // read sources.list and find match + vector<metaIndex *>::const_iterator I; + pkgSourceList list; + list.ReadMainList(); + for(I=list.begin(); I != list.end(); I++) + { + string uristr = (*I)->GetURI(); + if(Debug) + std::cerr << "Checking: " << uristr << std::endl; + if(uristr.substr(0,strlen("mirror://")) != string("mirror://")) + continue; + // find matching uri in sources.list + if(mirror_uri_str.substr(0,uristr.size()) == uristr) + { + if(Debug) + std::cerr << "found BaseURI: " << uristr << std::endl; + BaseUri = uristr.substr(0,uristr.size()-1); + } + } + string fetch = BaseUri; + fetch.replace(0,strlen("mirror://"),"http://"); + + // get new file + MirrorFile = _config->FindDir("Dir::State::mirrors") + URItoFileName(BaseUri); + + if(Debug) + { + cerr << "base-uri: " << BaseUri << endl; + cerr << "mirror-file: " << MirrorFile << endl; + } + + // check the file, if it is not older than RefreshInterval just use it + // otherwise try to get a new one + if(FileExists(MirrorFile)) + { + struct stat buf; + time_t t,now,refresh; + if(stat(MirrorFile.c_str(), &buf) != 0) + return false; + t = std::max(buf.st_mtime, buf.st_ctime); + now = time(NULL); + refresh = 60*_config->FindI("Acquire::Mirror::RefreshInterval",360); + if(t + refresh > now) + { + if(Debug) + clog << "Mirror file is in RefreshInterval" << endl; + HasMirrorFile = true; + return true; + } + if(Debug) + clog << "Mirror file " << MirrorFile << " older than " << refresh << "min, re-download it" << endl; + } + + // not that great to use pkgAcquire here, but we do not have + // any other way right now + pkgAcquire Fetcher; + new pkgAcqFile(&Fetcher, fetch, "", 0, "", "", "", MirrorFile); + bool res = (Fetcher.Run() == pkgAcquire::Continue); + if(res) + HasMirrorFile = true; + Fetcher.Shutdown(); + return res; +} + +bool MirrorMethod::SelectMirror() +{ + // FIXME: make the mirror selection more clever, do not + // just use the first one! + ifstream in(MirrorFile.c_str()); + getline(in, Mirror); + if(Debug) + cerr << "Using mirror: " << Mirror << endl; + + UsedMirror = Mirror; + return true; +} + +// MirrorMethod::Fetch - Fetch an item /*{{{*/ +// --------------------------------------------------------------------- +/* This adds an item to the pipeline. We keep the pipeline at a fixed + depth. */ +bool MirrorMethod::Fetch(FetchItem *Itm) +{ + // select mirror only once per session + if(!HasMirrorFile) + { + Clean(_config->FindDir("Dir::State::mirrors")); + GetMirrorFile(Itm->Uri); + SelectMirror(); + } + + for (FetchItem *I = Queue; I != 0; I = I->Next) + { + if(I->Uri.find("mirror://") != string::npos) + I->Uri.replace(0,BaseUri.size(),Mirror); + } + + // now run the real fetcher + return HttpMethod::Fetch(Itm); +}; + +void MirrorMethod::Fail(string Err,bool Transient) +{ + if(Queue->Uri.find("http://") != string::npos) + Queue->Uri.replace(0,Mirror.size(), BaseUri); + pkgAcqMethod::Fail(Err, Transient); +} + +void MirrorMethod::URIStart(FetchResult &Res) +{ + if(Queue->Uri.find("http://") != string::npos) + Queue->Uri.replace(0,Mirror.size(), BaseUri); + pkgAcqMethod::URIStart(Res); +} + +void MirrorMethod::URIDone(FetchResult &Res,FetchResult *Alt) +{ + if(Queue->Uri.find("http://") != string::npos) + Queue->Uri.replace(0,Mirror.size(), BaseUri); + pkgAcqMethod::URIDone(Res, Alt); +} + + +int main() +{ + setlocale(LC_ALL, ""); + + MirrorMethod Mth; + + return Mth.Loop(); +} + + diff --git a/methods/mirror.h b/methods/mirror.h new file mode 100644 index 000000000..798f5a9b5 --- /dev/null +++ b/methods/mirror.h @@ -0,0 +1,51 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/// $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ +// $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ +/* ###################################################################### + + MIRROR Aquire Method - This is the MIRROR aquire method for APT. + + ##################################################################### */ + /*}}}*/ + +#ifndef APT_MIRROR_H +#define APT_MIRROR_H + + +#include <iostream> + +using std::cout; +using std::cerr; +using std::endl; + +#include "http.h" + +class MirrorMethod : public HttpMethod +{ + FetchResult Res; + // we simply transform between BaseUri and Mirror + string BaseUri; // the original mirror://... url + string Mirror; // the selected mirror uri (http://...) + string MirrorFile; // + bool HasMirrorFile; + + bool Debug; + + protected: + bool GetMirrorFile(string uri); + bool SelectMirror(); + bool Clean(string dir); + + // we need to overwrite those to transform the url back + virtual void Fail(string Why, bool Transient = false); + virtual void URIStart(FetchResult &Res); + virtual void URIDone(FetchResult &Res,FetchResult *Alt = 0); + virtual bool Configuration(string Message); + + public: + MirrorMethod(); + virtual bool Fetch(FetchItem *Itm); +}; + + +#endif |