+\r
+\r
+/*-----------------------------------------------------------------*/\r
+/* Are you looking for int main (int argc, char **argv) ? :-)) */\r
+/*-----------------------------------------------------------------*/\r
+\r
+program\r
+{\r
+ int i=0;\r
+ FILE *f=NULL;\r
+ char *str, *ptr, *d;\r
+ char *substring;\r
+ int class_count=0,ip_count=0;\r
+ int parent=1;\r
+ int just_flush=0;\r
+ int nodelay=0;\r
+ int just_preview=0; /* preview - generate just stats */\r
+ char *chain_forward, *chain_postrouting;\r
+ char *althosts=NULL;\r
+ \r
+ printf("\n\\r
+Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
+Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\\r
+iptables-restore & burst tunning & classify modification 0.7d by Ludva\n\\r
+Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
+\r
+ /*----- Boring... we have to check command line options first: ----*/\r
+ \r
+ arguments\r
+ {\r
+ argument("-c") { nextargument(config); }\r
+ argument("-h") { nextargument(althosts);}\r
+ argument("-d") { dry_run=1; }\r
+ argument("-f") { just_flush=1; }\r
+ argument("-9") { just_flush=9; }\r
+ argument("-p") { just_preview=1; }\r
+ argument("-n") { nodelay=1; }\r
+ argument("-l") { parse_ip_log(argc,argv); exit(0); }\r
+ argument("-m") { parse_ip_log(argc,argv); exit(0); }\r
+ argument("-y") { parse_ip_log(argc,argv); exit(0); }\r
+ argument("-?") { help(); exit(0); }\r
+ argument("--help") { help(); exit(0); }\r
+ argument("-v") { exit(0); } \r
+ argument("--version") { exit(0); } \r
+ }\r
+\r
+ if(dry_run)\r
+ puts("*** THIS IS JUST DRY RUN ! ***\n");\r
+\r
+ date(d); /* this is typical cll1.h macro */\r
+\r
+ /*-----------------------------------------------------------------*/\r
+ printf("Parsing configuration file %s ...\n", config);\r
+ /*-----------------------------------------------------------------*/\r
+ get_config(config);\r
+\r
+ if(althosts) hosts=althosts;\r
+\r
+ if(just_flush<9)\r
+ {\r
+ /*-----------------------------------------------------------------*/\r
+ puts("Parsing iptables verbose output ...");\r
+ /*-----------------------------------------------------------------*/\r
+ get_traffic_statistics();\r
+ }\r
+\r
+ /*-----------------------------------------------------------------*/\r
+ printf("Parsing class defintion file %s ...\n", hosts);\r
+ /*-----------------------------------------------------------------*/\r
+ int groupidx = FIRSTGROUPID;\r
+ parse(hosts)\r
+ {\r
+ str=_;\r
+\r
+ if(*str<'0' || *str>'9')\r
+ continue;\r
+ \r
+ //Does this IP share QoS class with some other ?\r
+ substring=strstr(str,"sharing-");\r
+ if(substring)\r
+ { \r
+ substring+=8; //"sharing-"\r
+ parse_ip(str);\r
+ ip_count++;\r
+ ip->sharing=substring;\r
+ ip->keyword=defaultkeyword; /* settings for default keyword */\r
+ while(*substring && *substring!='\n')\r
+ substring++;\r
+ *substring=0; \r
+ }\r
+ else\r
+ {\r
+ //Do we have to create new QoS class for this IP ?\r
+\r
+ find(keyword,keywords,(substring=strstr(str,keyword->key)))\r
+ {\r
+ parse_ip(str);\r
+ ip_count++;\r
+ ip->keyword=keyword;\r
+ keyword->ip_count++;\r
+ ip->prio=keyword->default_prio;\r
+ substring+=strlen(keyword->key)+1;\r
+ ptr=substring;\r
+ while(*ptr && *ptr!='-')\r
+ ptr++;\r
+ if(*ptr=='-')\r
+ {\r
+ *ptr=0;\r
+ ip->max=ip->desired=atoi(ptr+1);\r
+ }\r
+ ip->min=atoi(substring);\r
+ if(ip->min<=0)\r
+ {\r
+ puts("Illegal value of minimum bandwidth: 0 kbps.");\r
+ reject_config_and_exit(hosts);\r
+ }\r
+ if(ip->max<=ip->min)\r
+ {\r
+ ip->fixedprio=1;\r
+ ip->max=ip->min+ip->keyword->reserve_min;\r
+ }\r
+ else \r
+ {\r
+ ip->max-=ip->keyword->reserve_max;\r
+\r
+/*\r
+ if(ip->keyword->divide_max>1)\r
+ ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;\r
+ if(ip->keyword->htb_ceil_bonus_divide>0)\r
+ ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;\r
+*/\r
+ if(ip->max<ip->min)\r
+ ip->max=ip->min;\r
+ }\r
+ ip->mark=FIRSTIPCLASS+1+class_count++;\r
+\r
+ find(group,groups,group->min==ip->min) \r
+ { \r
+ group->count++; \r
+ group->desired+=ip->min;\r
+ ip->group = group->id; \r
+ }\r
+ else\r
+ {\r
+ create(group,Group);\r
+ group->min=ip->min;\r
+ group->id = groupidx++;\r
+ ip->group = group->id;\r
+\r
+ if(group->min<8) group->min=8;\r
+ /* Warning - this is maybe because of primitive tc namespace, can be fixed */\r
+ /* it is because class IDs are derived from min. bandwidth. - xCh */\r
+ //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;\r
+ \r
+ group->count=1;\r
+ group->desired=ip->min; \r
+ insert(group,groups,desc_order_by,min);\r
+ }\r
+ }//endif keyword-\r
+ }//endif sharing-\r
+ }\r
+ fail\r
+ {\r
+ perror(hosts);\r
+ exit(-1);\r
+ }\r
+ done;\r
+\r
+ /*-----------------------------------------------------------------*/\r
+ /* cll1.h - let's allocate brand new character buffer... */\r
+ /*-----------------------------------------------------------------*/\r
+ string(str,STRLEN); \r
+\r
+ /*-----------------------------------------------------------------*/\r
+ puts("Resolving shared connections ...");\r
+ /*-----------------------------------------------------------------*/\r
+ search(ip,ips,ip->sharing)\r
+ {\r
+ search(sharedip,ips,eq(sharedip->name,ip->sharing))\r
+ {\r
+ sharedip->traffic+=ip->traffic;\r
+ ip->traffic=0;\r
+ ip->mark=sharedip->mark; \r
+ break;\r
+ }\r
+ if(!sharedip)\r
+ printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);\r
+ }\r
+\r
+ if(enable_credit && just_flush<9)\r
+ {\r
+ /*-----------------------------------------------------------------*/\r
+ printf("Parsing credit file %s ...\n", credit);\r
+ /*-----------------------------------------------------------------*/\r
+ parse(credit)\r
+ {\r
+ ptr=parse_datafile_line(_);\r
+ if(ptr)\r
+ {\r
+ find(ip,ips,eq(ip->addr,_))\r
+ sscanf(ptr,"%Lu",&(ip->credit));\r
+ }\r
+ }\r
+ done;\r
+ }\r
+\r
+ if(!just_preview)\r
+ {\r
+ /*-----------------------------------------------------------------*/\r
+ puts("Initializing iptables and tc classes ...");\r
+ /*-----------------------------------------------------------------*/\r
+ \r
+ iptables_file=fopen(iptablesfile,"w");\r
+ if (iptables_file == NULL) {\r
+ puts("Cannot open iptablesfile!");\r
+ exit(-1);\r
+ }\r
+ \r
+ log_file=fopen(cmdlog,"w");\r
+ if (log_file == NULL) {\r
+ puts("Cannot open logfile!");\r
+ exit(-1);\r
+ }\r
+ \r
+ save_line(iptablespreamble);\r
+ run_restore();\r
+ \r
+ sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
+ safe_run(str);\r
+\r
+ sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
+ safe_run(str);\r
+ \r
+ iptables_file=fopen(iptablesfile,"w");\r
+ save_line(iptablespreamble);\r
+\r
+ if(qos_free_zone && *qos_free_zone!='0')\r
+ {\r
+ char *chain;\r
+ \r
+ sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
+ save_line(str);\r
+ \r
+ if(qos_proxy)\r
+ {\r
+ save_line(":post_noproxy - [0:0]");\r
+ sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);\r
+ save_line(str); \r
+ sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);\r
+ save_line(str); \r
+ sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
+ save_line(str); \r
+\r
+ chain="post_noproxy"; \r
+ }\r
+ else\r
+ chain="POSTROUTING";\r
+ \r
+ sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
+ save_line(str);\r
+ }\r
+ \r
+ if(ip_count>idxtable_treshold1 && !just_flush)\r
+ {\r
+ int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */\r
+ char *subnet, *buf;\r
+ /*-----------------------------------------------------------------*/\r
+ printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
+ /*-----------------------------------------------------------------*/\r
+\r
+ save_line(":post_common - [0:0]");\r
+ save_line(":forw_common - [0:0]");\r
+\r
+ search(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))\r
+ {\r
+ buf=hash_id(ip->addr,bitmask);\r
+ find(idx,idxs,eq(idx->id,buf))\r
+ idx->children++;\r
+ else\r
+ {\r
+ create(idx,Index);\r
+ idx->addr=ip->addr;\r
+ idx->id=buf;\r
+ idx->bitmask=bitmask;\r
+ idx->parent=NULL;\r
+ idx->children=0;\r
+ idxcount++;\r
+ push(idx,idxs);\r
+ }\r
+ }\r
+\r
+ /* brutal perfomance optimalization */\r
+ while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)\r
+ {\r
+ bitmask-=idxtable_bitmask2;\r
+ idxcount=0;\r
+ search(idx,idxs,idx->parent==NULL)\r
+ {\r
+ buf=hash_id(idx->addr,bitmask);\r
+ find(metaindex,idxs,eq(metaindex->id,buf))\r
+ metaindex->children++; \r
+ else\r
+ {\r
+ create(metaindex,Index);\r
+ metaindex->addr=idx->addr;\r
+ metaindex->id=buf;\r
+ metaindex->bitmask=bitmask;\r
+ metaindex->parent=NULL;\r
+ metaindex->children=0;\r
+ idxcount++;\r
+ push(metaindex,idxs);\r
+ }\r
+ idx->parent=metaindex;\r
+ }\r
+ }\r
+\r
+ /* this should slightly optimize throughout ... */\r
+ sort(idx,idxs,desc_order_by,children);\r
+ sort(idx,idxs,order_by,bitmask);\r
+\r
+ i=0;\r
+ every(idx,idxs)\r
+ {\r
+ subnet=subnet_id(idx->addr,idx->bitmask);\r
+ printf("%d: %s/%d\n",++i,subnet,idx->bitmask);\r
+ \r
+ sprintf(str,":post_%s - [0:0]", idx->id);\r
+ save_line(str);\r
+\r
+ sprintf(str,":forw_%s - [0:0]", idx->id);\r
+ save_line(str);\r
+\r
+ if(idx->parent)\r
+ {\r
+ string(buf,strlen(idx->parent->id)+6);\r
+ sprintf(buf,"post_%s",idx->parent->id);\r
+ }\r
+ else\r
+ buf="POSTROUTING";\r
+\r
+ sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
+ save_line(str);\r
+\r
+ sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
+ save_line(str);\r
+\r
+ if(idx->parent)\r
+ {\r
+ string(buf,strlen(idx->parent->id)+6);\r
+ sprintf(buf,"forw_%s",idx->parent->id);\r
+ }\r
+ else\r
+ buf="FORWARD";\r
+\r
+ sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
+ save_line(str);\r
+\r
+ sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
+ save_line(str);\r
+ }\r
+ printf("Total indexed iptables chains created: %d\n", i);\r
+\r
+ sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
+ save_line(str);\r
+ \r
+ sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
+ save_line(str);\r
+ }\r
+ \r
+ }\r
+\r
+ if(just_flush)\r
+ {\r
+ fclose(iptables_file);\r
+ if (log_file) fclose(log_file);\r
+ puts("Just flushed iptables and tc classes - now exiting ...");\r
+ exit(0);\r
+ }\r
+\r
+ if(!just_preview)\r
+ {\r
+ if(!dry_run && !nodelay && qos_free_delay)\r
+ {\r
+ printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
+ sleep(qos_free_delay);\r
+ }\r
+\r
+ sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);\r
+ safe_run(str);\r
+\r
+ sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,lan,lan_medium,lan_medium,burst_main);\r
+ safe_run(str);\r
+\r
+ sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc,lan,line,line,burst_main);\r
+ safe_run(str);\r
+\r
+ sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
+ safe_run(str);\r
+\r
+ sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,wan,wan_medium,wan_medium,burst_main);\r
+ safe_run(str);\r
+\r
+ sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc,wan,up,up,burst_main);\r
+ safe_run(str);\r
+ }\r
+\r
+ /*-----------------------------------------------------------------*/\r
+ puts("Locating suckers and generating root classes ...");\r
+ /*-----------------------------------------------------------------*/\r
+ sort(ip,ips,desc_order_by,traffic);\r
+ \r
+\r
+ /*-----------------------------------------------------------------*/\r
+ /* sub-scope - local variables */ \r
+ {\r
+ long long int rate=line;\r
+ long long int max=line;\r
+ int group_count=0;\r
+ FILE *credit_file=NULL;\r
+ \r
+ if(!just_preview && !dry_run && enable_credit) credit_file=fopen(credit,"w");\r
+ \r
+ every(group,groups)\r
+ {\r
+ if(!just_preview)\r
+ {\r
+ \r
+ //download\r
+ sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio 1 #down desired %d", \r
+ tc, lan, parent, group->id, rate, max, burst_group, group->desired);\r
+ safe_run(str);\r
+ \r
+ //upload\r
+ sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio 1 #up desired %d", \r
+ tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, group->desired);\r
+ safe_run(str);\r
+ }\r
+ \r
+ if(group_count++<max_nesting) parent=group->id;\r
+ \r
+ rate-=digital_divide*group->min;\r
+ if(rate<group->min)rate=group->min;\r
+ \r
+ /*shaping of aggresive downloaders, with credit file support */\r
+ if(use_credit)\r
+ {\r
+ int group_rate=group->min, priority_sequence=magic_priorities+1;\r
+ \r
+ search(ip, ips, ip->min==group->min && ip->max>ip->min)\r
+ {\r
+ if( ip->keyword->data_limit && !ip->fixedprio &&\r
+ ip->traffic>ip->credit+\r
+ (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) )\r
+ {\r
+ if(group_rate<ip->max) ip->max=group_rate;\r
+ group_rate+=magic_treshold;\r
+ ip->prio=magic_priorities+2;\r
+ if(ip->prio<3) ip->prio=3;\r
+ }\r
+ else\r
+ {\r
+ if( ip->keyword->data_prio && !ip->fixedprio &&\r
+ ip->traffic>ip->credit+\r
+ (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20)) )\r
+ {\r
+ ip->prio=priority_sequence--;\r
+ if(ip->prio<2) ip->prio=2;\r
+ }\r
+ \r
+ if(credit_file)\r
+ {\r
+ unsigned long long lcredit=0;\r
+ \r
+ if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic) \r
+ lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
+ fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
+ }\r
+ }\r
+ }\r
+ \r
+ }\r
+ }\r
+ if(credit_file)fclose(credit_file);\r
+ }\r
+\r
+ if(just_preview)\r
+ {\r
+ f=fopen(preview,"w");\r
+ ptr=preview; \r
+ }\r
+ else if(!dry_run && !just_flush)\r
+ {\r
+ /*-----------------------------------------------------------------*/\r
+ printf("Writing data transfer database ...\n");\r
+ /*-----------------------------------------------------------------*/\r
+ f=fopen("/var/run/prometheus.previous","w");\r
+ if(f)\r
+ {\r
+ search(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)\r
+ fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);\r
+ fclose(f);\r
+ }\r
+\r
+ f=fopen(html,"w");\r
+ ptr=html;\r
+ }\r
+\r
+ if(f)\r
+ {\r
+ int total=0;\r
+ int count=1;\r
+ i=0;\r
+\r
+ /*-----------------------------------------------------------------*/\r
+ printf("Sorting data and generating statistics page %s ...\n",ptr);\r
+ /*-----------------------------------------------------------------*/\r
+\r
+ fputs("<table border>\n<tr><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f);\r
+ fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);\r
+ fputs("</tr>\n",f);\r
+ every(group,groups) \r
+ { \r
+#ifdef DEBUG\r
+ printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);\r
+#endif\r
+ fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);\r
+ fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);\r
+\r
+ every(keyword,keywords)\r
+ fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit); \r
+ \r
+ i+=group->desired; \r
+ total+=group->count;\r
+ count++; \r
+ }\r
+#ifdef DEBUG\r
+ printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);\r
+#endif\r
+ fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);\r
+ fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);\r
+\r
+ every(keyword,keywords)\r
+ fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count); \r
+\r
+ fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));\r
+ fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);\r
+\r
+ fputs("</table>\n",f);\r
+ }\r
+ else if(!dry_run && !just_flush) \r
+ perror(html);\r
+\r
+ i=1;\r
+ if(f)\r
+ {\r
+ unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;\r
+ int active_classes=0;\r
+ int colspan;\r
+ FILE *iplog;\r
+ struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;\r
+\r
+ if(qos_proxy)\r
+ colspan=12;\r
+ else \r
+ colspan=11;\r
+ \r
+ fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);\r
+ fprintf(f," (%s)</th></tr>\n", d);\r
+ fputs("<tr><td align=\"right\">#</td><td>hostname</td>\\r
+ <td align=\"right\">credit</td>\\r
+ <td align=\"right\">limit</td>\\r
+ <td align=\"right\">total</td>\\r
+ <td align=\"right\">direct</td>\n",f);\r
+ if(qos_proxy)\r
+ fputs("<td align=\"right\">proxy</td>\n",f);\r
+ fputs("<td align=\"right\">upload</td>\\r
+ <td align=\"right\">minimum</td>\\r
+ <td align=\"right\">desired</td>\\r
+ <td align=\"right\">maximum</td>\\r
+ <td>prio</td></tr>\n",f); \r
+\r
+ every(ip,ips)\r
+ {\r
+ char *f1="", *f2="";\r
+ if(ip->max<ip->desired)\r
+ {\r
+ f1="<font color=\"red\">";\r
+ f2="</font>";\r
+ }\r
+ else if(ip->prio>1)\r
+ {\r
+ f1="<font color=\"brown\">";\r
+ f2="</font>";\r
+ }\r
+\r
+#ifdef DEBUG\r
+ printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max); \r
+#endif\r
+ fprintf(f,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td><td align=\"right\">%Lu M</td>\n",\r
+ ip->name, i, log_url, ip->name, ip->name, ip->credit);\r
+ fprintf(f,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",ip->keyword->html_color,ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));\r
+ fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);\r
+ if(qos_proxy)\r
+ fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);\r
+ fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);\r
+ fprintf(f,"<td align=\"right\">%d k</td><td align=\"right\">%d k</td><td align=\"right\">%s%d k%s</td><td>%s%d%s</td></tr>\n",ip->min,ip->desired,f1,ip->max,f2,f1,ip->prio,f2);\r
+ total+=ip->traffic;\r
+ total_direct+=ip->direct;\r
+ total_proxy+=ip->proxy;\r
+ total_upload+=ip->upload;\r
+ if(ip->traffic>0)\r
+ {\r
+ active_classes++;\r
+ tmp_sum+=ip->traffic;\r
+ create(sum,Sum);\r
+ sum->l=tmp_sum;\r
+ sum->i=active_classes;\r
+ insert(sum,sums,order_by,i);\r
+ }\r
+ \r
+ i++;\r
+ \r
+ if(!just_preview)\r
+ {\r
+ sprintf(str,"%s/%s.log",log_dir,ip->name);\r
+ iplog=fopen(str,"a");\r
+ if(iplog)\r
+ {\r
+ fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%s",time(NULL),ip->name,ip->traffic, ip->direct, ip->proxy, ip->upload,d);\r
+ fclose(iplog);\r
+ }\r
+ }\r
+\r
+ }\r
+ fprintf(f,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");\r
+ fprintf(f,"<th align=\"right\">%Lu M</th>\\r
+ <th align=\"right\">%Lu M</th>\n", total, total_direct);\r
+ if(qos_proxy)\r
+ fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);\r
+ fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);\r
+ fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);\r
+\r
+ if(active_classes>10)\r