/* server.* - nget configuration handling Copyright (C) 2000-2003 Matthew Mueller 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 2 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "server.h" #include "strreps.h" #include "nget.h" #include "status.h" #include #include #include bool c_nget_config::penalize(c_server::ptr server) const { if (penaltystrikes<=0) return false;//penalization disabled ++server->penalty_count; if (server->penalty_count == penaltystrikes) { server->penalty_time = initialpenalty; } else if (server->penalty_count > penaltystrikes) { server->penalty_time = (time_t)(server->penalty_time * penaltymultiplier); } server->last_penalty = time(NULL); PDEBUG(DEBUG_MED, "penalized %s: count %i, last %li, time %li", server->alias.c_str(), server->penalty_count, server->last_penalty, server->penalty_time); return server->penalty_count >= penaltystrikes; } c_server::ptr c_nget_config::getserver(const string &name) const { serv_match_by_name name_matcher; name_matcher.mname=name.c_str(); t_server_list::const_iterator sli=find_if(serv.begin(),serv.end(),name_matcher); if (sli!=serv.end()) return (*sli).second; return NULL; } int parse_int_pair(const char *s, int *l, int *h){ const char *p; char *erp; int i; if (!s || *s=='\0')return -1; p=strchr(s,','); if (p){ int i2; p++; if (*p=='\0')return -1; i=strtol(s,&erp,0); if (*erp!=',') return -1; i2=strtol(p,&erp,0); if (*erp!='\0') return -1; if (i<=i2){ *l=i;*h=i2; }else{ *l=i2;*h=i; } }else{ i=strtol(s,&erp,0); if (*erp!='\0') return -1; if (i<0)i=-i; *l=-i;*h=i; } return 0; } c_server::c_server(ulong id, const CfgSection *ds) : serverid(id), alias(ds->key) { addr = ds->gets("addr"); user = ds->gets("user"); pass = ds->gets("pass"); shortname = ds->gets("shortname"); if (shortname.empty()) shortname = alias[0]; ds->get("idletimeout",idletimeout,1,INT_MAX,nconfig.idletimeout); ds->get("fullxover",fullxover,0,2,nconfig.fullxover); ds->get("maxstreaming",maxstreaming,0,INT_MAX,nconfig.maxstreaming); if (ds->getitem("linelenience")){ const char *ll = ds->geta("linelenience"); int l,h; if (!parse_int_pair(ll,&l,&h)){ lineleniencelow=l;lineleniencehigh=h; }else{ PERROR("%s: invalid linelenience %s",ds->name().c_str(),ll); set_user_error_status(); lineleniencelow=lineleniencehigh=0; } }else{ lineleniencelow=lineleniencehigh=0; } penalty_count=0; last_penalty=0; penalty_time=0; } void c_nget_config::setlist(const CfgSection *cfg,const CfgSection *hinfo,const CfgSection *pinfo,const CfgSection *ginfo){ c_server::ptr server; CfgSection_map::const_iterator dli; CfgItem_map::const_iterator dii; const CfgSection *ds; const CfgItem *di; ulong tul; //cfg assert(cfg); cfg->get("curservmult",curservmult); cfg->get("usegz",usegz,-1,9); cfg->get("fullxover", fullxover, 0, 2); cfg->get("fatal_user_errors", fatal_user_errors, false, true); cfg->get("autopar_optimistic", autopar_optimistic, false, true); cfg->get("unequal_line_error",unequal_line_error,0,1); cfg->get("maxstreaming",maxstreaming,0,INT_MAX); cfg->get("maxconnections",maxconnections,-1,INT_MAX); cfg->get("idletimeout",idletimeout,1,INT_MAX); cfg->get("penaltystrikes",penaltystrikes,-1,INT_MAX); cfg->get("initialpenalty",initialpenalty,1,INT_MAX); cfg->get("penaltymultiplier",penaltymultiplier,1.0f,1e100f); //halias assert(hinfo); for (dli=hinfo->sections_begin();dli!=hinfo->sections_end();++dli){ ds=(*dli).second; assert(ds); if (!ds->getitem("addr")){ PERROR("host %s no addr",ds->key.c_str()); set_user_error_status(); continue; } if (!ds->getitem("id")){ PERROR("host %s no id",ds->key.c_str()); set_user_error_status(); continue; } if (!ds->get("id",tul,1UL,ULONG_MAX)) continue; server = new c_server(tul, ds); serv.insert(t_server_list::value_type(server->serverid,server)); } //hpriority if (pinfo) for (dli=pinfo->sections_begin();dli!=pinfo->sections_end();++dli){ ds=(*dli).second; assert(ds); c_server_priority_grouping *pgrouping=new c_server_priority_grouping(ds->key); for (dii=ds->items_begin();dii!=ds->items_end();++dii){ di=(*dii).second; if (di->key=="_level"){ di->get(pgrouping->deflevel); }else if (di->key=="_glevel"){ di->get(pgrouping->defglevel); }else{ server=getserver(di->key); if (!server){ PERROR("prio section %s, server %s not found",ds->key.c_str(),di->key.c_str()); set_user_error_status(); continue; } c_server_priority *sprio=new c_server_priority(server,atof(di->gets().c_str())); pgrouping->priorities.insert(t_server_priority_grouping::value_type(sprio->server,sprio)); } } if (pgrouping->alias=="trustsizes") trustsizes=pgrouping; else prioritygroupings.insert(t_server_priority_grouping_list::value_type(pgrouping->alias.c_str(),pgrouping)); } if (getpriogrouping("default")==NULL){ c_server_priority_grouping *pgrouping=new c_server_priority_grouping("default"); prioritygroupings.insert(t_server_priority_grouping_list::value_type(pgrouping->alias.c_str(),pgrouping)); } if (trustsizes==NULL){ trustsizes=new c_server_priority_grouping("trustsizes"); } //galias if (ginfo) { for (dii=ginfo->items_begin();dii!=ginfo->items_end();++dii){ di=(*dii).second; addgroup_or_metagroup(di->key,di->gets()); } for (dli=ginfo->sections_begin();dli!=ginfo->sections_end();++dli){ ds=(*dli).second; assert(ds); int susegz; ds->get("usegz",susegz,-1,9,-2); addgroup(ds->key,ds->gets("group"),ds->gets("prio"),susegz); } } } void c_nget_config::addgroup_or_metagroup(const string &alias, const string &name){ if (name.find(',')!=string::npos) addmetagroup(alias,name); else addgroup(alias,name,""); } void c_nget_config::addmetagroup(const string &alias, const string &name){ metagroups.insert(t_metagroup_list::value_type(alias,name)); } c_group_info::ptr c_nget_config::addgroup(const string &alias, const string &name, string prio, int usegz){ if (prio.empty())prio="default"; c_server_priority_grouping *priog=getpriogrouping(prio); if (!priog){ printf("group %s(%s), prio %s not found\n",name.c_str(),alias.c_str(),prio.c_str()); set_user_error_status(); return NULL; } assert(priog); c_group_info::ptr group(new c_group_info(alias,name,priog,usegz)); if (group){ if (!alias.empty()) groups.insert(t_group_info_list::value_type(group->alias.c_str(),group)); groups.insert(t_group_info_list::value_type(group->group.c_str(),group)); } return group; } void c_nget_config::dogetallcachedgroups(vector &groups) { DIR *dir=opendir(ngcachehome.c_str()); struct dirent *de; if (!dir) throw PathExFatal(Ex_INIT,"opendir: %s(%i)",strerror(errno),errno); while ((de=readdir(dir))) { char *endp; if ((endp=strstr(de->d_name,",cache"))){ string groupname(de->d_name, endp - de->d_name); groups.push_back(getgroup(groupname.c_str())); } } closedir(dir); } void c_nget_config::dogetgroups(vector &groups, const char *names) { char *foo = new char[strlen(names)+1]; char *cur = foo, *name = NULL; strcpy(foo, names); while ((name = goodstrtok(&cur, ','))) { if (strcmp(name,"*")==0) dogetallcachedgroups(groups); else { t_metagroup_list::const_iterator mgi=metagroups.find(name); if (mgi!=metagroups.end()) dogetgroups(groups, mgi->second.c_str()); else groups.push_back(getgroup(name)); } } delete [] foo; } void c_nget_config::getgroups(vector &groups, const char *names) { groups.clear(); vector tmpgroups; dogetgroups(tmpgroups, names); for (vector::const_iterator gi=tmpgroups.begin(); gi!=tmpgroups.end(); ++gi) if (find(groups.begin(), groups.end(), *gi)==groups.end()) groups.push_back(*gi); // return only unique groups }