1 /*
2 server.* - nget configuration handling
3 Copyright (C) 2000-2003 Matthew Mueller <donut AT dakotacom.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include "server.h"
20 #include "strreps.h"
21 #include "nget.h"
22 #include "status.h"
23 #include <sys/types.h>
24 #include <dirent.h>
25 #include <algorithm>
26
penalize(c_server::ptr server) const27 bool c_nget_config::penalize(c_server::ptr server) const {
28 if (penaltystrikes<=0)
29 return false;//penalization disabled
30 ++server->penalty_count;
31 if (server->penalty_count == penaltystrikes) {
32 server->penalty_time = initialpenalty;
33 }
34 else if (server->penalty_count > penaltystrikes) {
35 server->penalty_time = (time_t)(server->penalty_time * penaltymultiplier);
36 }
37 server->last_penalty = time(NULL);
38 PDEBUG(DEBUG_MED, "penalized %s: count %i, last %li, time %li", server->alias.c_str(), server->penalty_count, server->last_penalty, server->penalty_time);
39 return server->penalty_count >= penaltystrikes;
40 }
41
getserver(const string & name) const42 c_server::ptr c_nget_config::getserver(const string &name) const {
43 serv_match_by_name name_matcher;
44 name_matcher.mname=name.c_str();
45 t_server_list::const_iterator sli=find_if(serv.begin(),serv.end(),name_matcher);
46 if (sli!=serv.end())
47 return (*sli).second;
48 return NULL;
49 }
50
parse_int_pair(const char * s,int * l,int * h)51 int parse_int_pair(const char *s, int *l, int *h){
52 const char *p;
53 char *erp;
54 int i;
55 if (!s || *s=='\0')return -1;
56 p=strchr(s,',');
57 if (p){
58 int i2;
59 p++;
60 if (*p=='\0')return -1;
61 i=strtol(s,&erp,0);
62 if (*erp!=',')
63 return -1;
64 i2=strtol(p,&erp,0);
65 if (*erp!='\0')
66 return -1;
67 if (i<=i2){
68 *l=i;*h=i2;
69 }else{
70 *l=i2;*h=i;
71 }
72 }else{
73 i=strtol(s,&erp,0);
74 if (*erp!='\0')
75 return -1;
76 if (i<0)i=-i;
77 *l=-i;*h=i;
78 }
79 return 0;
80 }
81
c_server(ulong id,const CfgSection * ds)82 c_server::c_server(ulong id, const CfgSection *ds) : serverid(id), alias(ds->key) {
83 addr = ds->gets("addr");
84 user = ds->gets("user");
85 pass = ds->gets("pass");
86 shortname = ds->gets("shortname");
87 if (shortname.empty()) shortname = alias[0];
88 ds->get("idletimeout",idletimeout,1,INT_MAX,nconfig.idletimeout);
89 ds->get("fullxover",fullxover,0,2,nconfig.fullxover);
90 ds->get("maxstreaming",maxstreaming,0,INT_MAX,nconfig.maxstreaming);
91 if (ds->getitem("linelenience")){
92 const char *ll = ds->geta("linelenience");
93 int l,h;
94 if (!parse_int_pair(ll,&l,&h)){
95 lineleniencelow=l;lineleniencehigh=h;
96 }else{
97 PERROR("%s: invalid linelenience %s",ds->name().c_str(),ll);
98 set_user_error_status();
99 lineleniencelow=lineleniencehigh=0;
100 }
101 }else{
102 lineleniencelow=lineleniencehigh=0;
103 }
104
105 penalty_count=0;
106 last_penalty=0;
107 penalty_time=0;
108 }
109
setlist(const CfgSection * cfg,const CfgSection * hinfo,const CfgSection * pinfo,const CfgSection * ginfo)110 void c_nget_config::setlist(const CfgSection *cfg,const CfgSection *hinfo,const CfgSection *pinfo,const CfgSection *ginfo){
111 c_server::ptr server;
112 CfgSection_map::const_iterator dli;
113 CfgItem_map::const_iterator dii;
114 const CfgSection *ds;
115 const CfgItem *di;
116 ulong tul;
117 //cfg
118 assert(cfg);
119 cfg->get("curservmult",curservmult);
120 cfg->get("usegz",usegz,-1,9);
121 cfg->get("fullxover", fullxover, 0, 2);
122 cfg->get("fatal_user_errors", fatal_user_errors, false, true);
123 cfg->get("autopar_optimistic", autopar_optimistic, false, true);
124 cfg->get("unequal_line_error",unequal_line_error,0,1);
125 cfg->get("maxstreaming",maxstreaming,0,INT_MAX);
126 cfg->get("maxconnections",maxconnections,-1,INT_MAX);
127 cfg->get("idletimeout",idletimeout,1,INT_MAX);
128 cfg->get("penaltystrikes",penaltystrikes,-1,INT_MAX);
129 cfg->get("initialpenalty",initialpenalty,1,INT_MAX);
130 cfg->get("penaltymultiplier",penaltymultiplier,1.0f,1e100f);
131 //halias
132 assert(hinfo);
133 for (dli=hinfo->sections_begin();dli!=hinfo->sections_end();++dli){
134 ds=(*dli).second;
135 assert(ds);
136 if (!ds->getitem("addr")){
137 PERROR("host %s no addr",ds->key.c_str());
138 set_user_error_status();
139 continue;
140 }
141 if (!ds->getitem("id")){
142 PERROR("host %s no id",ds->key.c_str());
143 set_user_error_status();
144 continue;
145 }
146 if (!ds->get("id",tul,1UL,ULONG_MAX))
147 continue;
148 server = new c_server(tul, ds);
149 serv.insert(t_server_list::value_type(server->serverid,server));
150 }
151 //hpriority
152 if (pinfo)
153 for (dli=pinfo->sections_begin();dli!=pinfo->sections_end();++dli){
154 ds=(*dli).second;
155 assert(ds);
156 c_server_priority_grouping *pgrouping=new c_server_priority_grouping(ds->key);
157 for (dii=ds->items_begin();dii!=ds->items_end();++dii){
158 di=(*dii).second;
159 if (di->key=="_level"){
160 di->get(pgrouping->deflevel);
161 }else if (di->key=="_glevel"){
162 di->get(pgrouping->defglevel);
163 }else{
164 server=getserver(di->key);
165 if (!server){
166 PERROR("prio section %s, server %s not found",ds->key.c_str(),di->key.c_str());
167 set_user_error_status();
168 continue;
169 }
170 c_server_priority *sprio=new c_server_priority(server,atof(di->gets().c_str()));
171 pgrouping->priorities.insert(t_server_priority_grouping::value_type(sprio->server,sprio));
172 }
173 }
174 if (pgrouping->alias=="trustsizes")
175 trustsizes=pgrouping;
176 else
177 prioritygroupings.insert(t_server_priority_grouping_list::value_type(pgrouping->alias.c_str(),pgrouping));
178 }
179 if (getpriogrouping("default")==NULL){
180 c_server_priority_grouping *pgrouping=new c_server_priority_grouping("default");
181 prioritygroupings.insert(t_server_priority_grouping_list::value_type(pgrouping->alias.c_str(),pgrouping));
182 }
183 if (trustsizes==NULL){
184 trustsizes=new c_server_priority_grouping("trustsizes");
185 }
186 //galias
187 if (ginfo) {
188 for (dii=ginfo->items_begin();dii!=ginfo->items_end();++dii){
189 di=(*dii).second;
190 addgroup_or_metagroup(di->key,di->gets());
191 }
192 for (dli=ginfo->sections_begin();dli!=ginfo->sections_end();++dli){
193 ds=(*dli).second;
194 assert(ds);
195 int susegz;
196 ds->get("usegz",susegz,-1,9,-2);
197 addgroup(ds->key,ds->gets("group"),ds->gets("prio"),susegz);
198 }
199 }
200 }
201
addgroup_or_metagroup(const string & alias,const string & name)202 void c_nget_config::addgroup_or_metagroup(const string &alias, const string &name){
203 if (name.find(',')!=string::npos)
204 addmetagroup(alias,name);
205 else
206 addgroup(alias,name,"");
207 }
208
addmetagroup(const string & alias,const string & name)209 void c_nget_config::addmetagroup(const string &alias, const string &name){
210 metagroups.insert(t_metagroup_list::value_type(alias,name));
211 }
212
addgroup(const string & alias,const string & name,string prio,int usegz)213 c_group_info::ptr c_nget_config::addgroup(const string &alias, const string &name, string prio, int usegz){
214 if (prio.empty())prio="default";
215 c_server_priority_grouping *priog=getpriogrouping(prio);
216 if (!priog){
217 printf("group %s(%s), prio %s not found\n",name.c_str(),alias.c_str(),prio.c_str());
218 set_user_error_status();
219 return NULL;
220 }
221 assert(priog);
222 c_group_info::ptr group(new c_group_info(alias,name,priog,usegz));
223 if (group){
224 if (!alias.empty())
225 groups.insert(t_group_info_list::value_type(group->alias.c_str(),group));
226 groups.insert(t_group_info_list::value_type(group->group.c_str(),group));
227 }
228 return group;
229 }
230
dogetallcachedgroups(vector<c_group_info::ptr> & groups)231 void c_nget_config::dogetallcachedgroups(vector<c_group_info::ptr> &groups) {
232 DIR *dir=opendir(ngcachehome.c_str());
233 struct dirent *de;
234 if (!dir)
235 throw PathExFatal(Ex_INIT,"opendir: %s(%i)",strerror(errno),errno);
236 while ((de=readdir(dir))) {
237 char *endp;
238 if ((endp=strstr(de->d_name,",cache"))){
239 string groupname(de->d_name, endp - de->d_name);
240 groups.push_back(getgroup(groupname.c_str()));
241 }
242 }
243 closedir(dir);
244 }
245
dogetgroups(vector<c_group_info::ptr> & groups,const char * names)246 void c_nget_config::dogetgroups(vector<c_group_info::ptr> &groups, const char *names) {
247 char *foo = new char[strlen(names)+1];
248 char *cur = foo, *name = NULL;
249 strcpy(foo, names);
250 while ((name = goodstrtok(&cur, ','))) {
251 if (strcmp(name,"*")==0)
252 dogetallcachedgroups(groups);
253 else {
254 t_metagroup_list::const_iterator mgi=metagroups.find(name);
255 if (mgi!=metagroups.end())
256 dogetgroups(groups, mgi->second.c_str());
257 else
258 groups.push_back(getgroup(name));
259 }
260 }
261 delete [] foo;
262 }
263
getgroups(vector<c_group_info::ptr> & groups,const char * names)264 void c_nget_config::getgroups(vector<c_group_info::ptr> &groups, const char *names) {
265 groups.clear();
266 vector<c_group_info::ptr> tmpgroups;
267 dogetgroups(tmpgroups, names);
268 for (vector<c_group_info::ptr>::const_iterator gi=tmpgroups.begin(); gi!=tmpgroups.end(); ++gi)
269 if (find(groups.begin(), groups.end(), *gi)==groups.end())
270 groups.push_back(*gi); // return only unique groups
271 }
272