qos-gargoyle: drop outdated packages

This commit is contained in:
CN_SZTL 2020-11-03 13:40:58 +08:00
parent 2a9aa40383
commit b2b4314348
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
52 changed files with 0 additions and 13710 deletions

View File

@ -114,13 +114,6 @@ $(eval $(call nf_add,IPT_FILTER,CONFIG_NETFILTER_XT_MATCH_BPF, $(P_XT)xt_bpf))
$(eval $(call nf_add,IPT_IMQ,CONFIG_IP_NF_TARGET_IMQ, $(P_V4)ipt_IMQ))
$(eval $(call nf_add,IPT_IMQ,CONFIG_NETFILTER_XT_TARGET_IMQ, $(P_XT)xt_IMQ))
# gargoyle-qos
$(eval $(call nf_add,IPT_BANDWIDTH,CONFIG_IP_NF_MATCH_BANDWIDTH, $(P_V4)ipt_bandwidth))
$(eval $(call nf_add,IPT_TIMERANGE,CONFIG_IP_NF_MATCH_TIMERANGE, $(P_V4)ipt_timerange))
$(eval $(call nf_add,IPT_WEBMON,CONFIG_IP_NF_MATCH_WEBMON, $(P_V4)ipt_webmon))
$(eval $(call nf_add,IPT_WEBURL,CONFIG_IP_NF_MATCH_WEBURL, $(P_V4)ipt_weburl))
# ipopt
$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_DSCP, $(P_XT)xt_dscp))

View File

@ -1,72 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gargoyle-firewall-util
PKG_VERSION:=$(GARGOYLE_VERSION)
ifeq ($(GARGOYLE_VERSION),)
PKG_VERSION:=1.0.0
endif
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/gargoyle-firewall-util
SECTION:=net
CATEGORY:=Network
TITLE:=A couple of shell script routines for firewall initialization
DEPENDS:=+ebtables +libericstools +uci +libiptbwctl +iptables-mod-filter +iptables-mod-ipopt +iptables-mod-conntrack-extra +iptables-mod-nat-extra +iptables-mod-extra +iptables-mod-iprange +iptables-mod-bandwidth +iptables-mod-timerange +iptables-mod-weburl +kmod-gre +kmod-pptp +kmod-tun +kmod-nf-nathelper +kmod-nf-nathelper-extra
MAINTAINER:=Eric Bishop <eric@gargoyle-router.com>
endef
define Package/gargoyle-firewall-util/description
A couple of shell script routines for firewall initialization
endef
define Build/Prepare
echo PACKAGE BUILD DIR = $(PACKAGE_BUILD_DIR)
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Configure
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
STAGING_DIR="$(STAGING_DIR)" \
CFLAGS="$(TARGET_CFLAGS) -I $(STAGING_DIR)/usr/include" \
LDFLAGS="$(TARGET_LDFLAGS) -L $(STAGING_DIR)/usr/lib"
endef
define Package/gargoyle-firewall-util/postinst
included=$$(cat $${IPKG_INSTROOT}/etc/config/firewall | grep 'gargoyle_additions.firewall' )
if [ -z "$$included" ] ; then printf "config include\n\toption type script\n\toption path /usr/lib/gargoyle_firewall_util/gargoyle_additions.firewall\n\toption family IPv4\n\toption reload 1\n\n" >> $${IPKG_INSTROOT}/etc/config/firewall ; fi
endef
define Package/gargoyle-firewall-util/install
$(INSTALL_DIR) $(1)/usr/lib/gargoyle_firewall_util/
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface/
$(INSTALL_DIR) $(1)/usr/bin/
$(INSTALL_DIR) $(1)/etc/init.d/
$(INSTALL_DIR) $(1)/etc/ppp/ip-up.d/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/make_iptables_rules $(1)/usr/bin/make_iptables_rules
$(INSTALL_BIN) $(PKG_BUILD_DIR)/delete_chain_from_table $(1)/usr/bin/delete_chain_from_table
$(INSTALL_BIN) $(PKG_BUILD_DIR)/backup_quotas $(1)/usr/bin/backup_quotas
$(INSTALL_BIN) $(PKG_BUILD_DIR)/restore_quotas $(1)/usr/bin/restore_quotas
$(INSTALL_BIN) $(PKG_BUILD_DIR)/print_quotas $(1)/usr/bin/print_quotas
$(INSTALL_BIN) ./files/gargoyle_firewall_util.sh $(1)/usr/lib/gargoyle_firewall_util/gargoyle_firewall_util.sh
$(INSTALL_BIN) ./files/gargoyle_additions.firewall $(1)/usr/lib/gargoyle_firewall_util/gargoyle_additions.firewall
$(INSTALL_BIN) ./files/gargoyle_firewall.hotplug $(1)/etc/hotplug.d/iface/21-gargoyle_firewall
$(INSTALL_BIN) ./files/set_kernel_timezone.init $(1)/etc/init.d/set_kernel_timezone
$(INSTALL_BIN) ./files/modemaccess.pppoe $(1)/etc/ppp/ip-up.d/modemaccess.sh
endef
$(eval $(call BuildPackage,gargoyle-firewall-util))

View File

@ -1,2 +0,0 @@
. /usr/lib/gargoyle_firewall_util/gargoyle_firewall_util.sh
initialize_firewall

View File

@ -1,40 +0,0 @@
if [ "$INTERFACE" = "wan" ]; then
. /usr/lib/gargoyle_firewall_util/gargoyle_firewall_util.sh
if [ "$ACTION" = "ifup" ]; then
# previously we waited until firewall was up here, testing firewall.core.loaded in /var/state
# unfortunately that was removed in barrier breaker, but new firewall (fw3) loads very FAST as it's a binary
# So... just wait 2 seconds
sleep 2
#Bring up the parts of the firewall that depend on device name and WAN IP address.
ifup_firewall
#Start up the bandwidth monitor which depends on the device name
if [ -h /etc/rc.d/S55bwmon_gargoyle ] ; then
/etc/init.d/bwmon_gargoyle restart
fi
fi
if [ "$ACTION" = "ifdown" ]; then
quota_chains_exist=$(iptables -t mangle -L combined_quotas 2>/dev/null)
if [ -n "$quota_chains_exist" ] ; then
backup_quotas
fi
fi
fi
if [ "$INTERFACE" = "lan" ]; then
wan_exists=$(uci get network.wan 2>/dev/null)
if [ -z "$wan_exists" ] ; then
if [ "$ACTION" = "ifup" ]; then
/etc/init.d/bwmon_gargoyle restart
fi
if [ "$ACTION" = "ifdown" ]; then
/etc/init.d/bwmon_gargoyle stop
fi
fi
fi

View File

@ -1,639 +0,0 @@
# Copyright Eric Bishop, 2008-2010
# This is free software licensed under the terms of the GNU GPL v2.0
#
. /lib/functions.sh
include /lib/network
ra_mask="0x0080"
ra_mark="$ra_mask/$ra_mask"
death_mask=0x8000
death_mark="$death_mask"
wan_if=""
mask_to_cidr()
{
mask="$1"
bits=0;
mask_parts=$(echo $mask | sed 's/\./ /g')
for p in $mask_parts ; do
case $p in
255)
bits=$(($bits + 8)) ;;
254)
bits=$(($bits + 7)) ;;
252)
bits=$(($bits + 6)) ;;
248)
bits=$(($bits + 5)) ;;
240)
bits=$(($bits + 4)) ;;
224)
bits=$(($bits + 3)) ;;
192)
bits=$(($bits + 2)) ;;
128)
bits=$(($bits + 1)) ;;
esac
done
echo $bits
}
define_wan_if()
{
if [ -z "$wan_if" ] ; then
#Wait for up to 15 seconds for the wan interface to indicate it is up.
wait_sec=15
while [ -z "$(uci -P /var/state get network.wan.up 2>/dev/null)" ] && [ "$wait_sec" -gt 0 ] ; do
sleep 1
wait_sec=$(($wait_sec - 1))
done
#The interface name will depend on if pppoe is used or not. If pppoe is used then
#the name we are looking for is in network.wan.ifname. If there is nothing there
#use the device named by network.wan.device
wan_if=$(uci -P /var/state get network.wan.ifname 2>/dev/null)
if [ -z "$wan_if" ] ; then
wan_if=$(uci -P /var/state get network.wan.device 2>/dev/null)
fi
fi
}
# parse remote_accept sections in firewall config and add necessary rules
insert_remote_accept_rules()
{
local config_name="firewall"
local section_type="remote_accept"
ssh_max_attempts=$(uci get dropbear.@dropbear[0].max_remote_attempts 2>/dev/null)
ssh_port=$(uci get dropbear.@dropbear[0].Port)
if [ -z "$ssh_max_attempts" ] || [ "$ssh_max_attempts" = "unlimited" ] ; then
ssh_max_attempts=""
else
ssh_max_attempts=$(( $ssh_max_attempts + 1 ))
fi
#add rules for remote_accepts
parse_remote_accept_config()
{
vars="local_port remote_port start_port end_port proto zone"
proto="tcp udp"
zone="wan"
for var in $vars ; do
config_get $var $1 $var
done
if [ "$proto" = "tcpudp" ] || [ -z "$proto" ] ; then
proto="tcp udp"
fi
for prot in $proto ; do
if [ -n "$local_port" ] ; then
if [ -z "$remote_port" ] ; then
remote_port="$local_port"
fi
#Discourage brute force attacks on ssh from the WAN by limiting failed conneciton attempts.
#Each attempt gets a maximum of 10 password tries by dropbear.
if [ -n "$ssh_max_attempts" ] && [ "$local_port" = "$ssh_port" ] && [ "$prot" = "tcp" ] ; then
iptables -t filter -A "input_${zone}_rule" -p "$prot" --dport $ssh_port -m recent --set --name SSH_CHECK
iptables -t filter -A "input_${zone}_rule" -m recent --update --seconds 300 --hitcount $ssh_max_attempts --name SSH_CHECK -j DROP
fi
if [ "$remote_port" != "$local_port" ] ; then
#since we're inserting with -I, insert redirect rule first which will then be hit second, after setting connmark
iptables -t nat -I "zone_"$zone"_prerouting" -p "$prot" --dport "$remote_port" -j REDIRECT --to-ports "$local_port"
iptables -t nat -I "zone_"$zone"_prerouting" -p "$prot" --dport "$remote_port" -j CONNMARK --set-mark "$ra_mark"
iptables -t filter -A "input_${zone}_rule" -p $prot --dport "$local_port" -m connmark --mark "$ra_mark" -j ACCEPT
else
iptables -t nat -I "zone_"$zone"_prerouting" -p "$prot" --dport "$remote_port" -j REDIRECT --to-ports "$local_port"
iptables -t filter -A "input_${zone}_rule" -p "$prot" --dport "$local_port" -j ACCEPT
fi
elif [ -n "$start_port" ] && [ -n "$end_port" ] ; then
iptables -t nat -I "zone_"$zone"_prerouting" -p "$prot" --dport "$start_port:$end_port" -j REDIRECT
iptables -t filter -A "input_${zone}_rule" -p "$prot" --dport "$start_port:$end_port" -j ACCEPT
fi
done
}
config_load "$config_name"
config_foreach parse_remote_accept_config "$section_type"
}
# creates a chain that sets third byte of connmark to a value that denotes what l7 proto
# is associated with connection. This only sets the connmark, it does not save it to mark
create_l7marker_chain()
{
# eliminate chain if it exists
delete_chain_from_table "mangle" "l7marker"
app_proto_num=1
app_proto_shift=16
app_proto_mask="0xFF0000"
all_prots=$(ls /etc/l7-protocols/* | sed 's/^.*\///' | sed 's/\.pat$//' )
qos_active=$(ls /etc/rc.d/*qos_gargoyle* 2>/dev/null)
if [ -n "$qos_active" ] ; then
qos_l7=$(uci show qos_gargoyle | sed '/layer7=/!d; s/^.*=//g')
fi
fw_l7=$(uci show firewall | sed '/app_proto/!d; s/^.*=//g')
all_used="$fw_l7 $qos_l7"
if [ "$all_used" != " " ] ; then
iptables -t mangle -N l7marker
iptables -t mangle -I PREROUTING -m connbytes --connbytes 0:20 --connbytes-dir both --connbytes-mode packets -m connmark --mark 0x0/$app_proto_mask -j l7marker
iptables -t mangle -I POSTROUTING -m connbytes --connbytes 0:20 --connbytes-dir both --connbytes-mode packets -m connmark --mark 0x0/$app_proto_mask -j l7marker
for proto in $all_prots ; do
proto_is_used=$(echo "$all_used" | grep "$proto")
if [ -n "$proto_is_used" ] ; then
app_proto_mark=$(printf "0x%X" $(($app_proto_num << $app_proto_shift)) )
iptables -t mangle -A l7marker -m connmark --mark 0x0/$app_proto_mask -m layer7 --l7proto $proto -j CONNMARK --set-mark $app_proto_mark/$app_proto_mask
echo "$proto $app_proto_mark $app_proto_mask" >> /tmp/l7marker.marks.tmp
app_proto_num=$((app_proto_num + 1))
fi
done
copy_file="y"
if [ -e /etc/md5/layer7.md5 ] ; then
old_md5=$(cat /etc/md5/layer7.md5)
current_md5=$(md5sum /tmp/l7marker.marks.tmp | awk ' { print $1 ; } ' )
if [ "$current_md5" = "$old_md5" ] ; then
copy_file="n"
fi
fi
if [ "$copy_file" = "y" ] ; then
mv /tmp/l7marker.marks.tmp /etc/l7marker.marks
mkdir -p /etc/md5
md5sum /etc/l7marker.marks | awk ' { print $1 ; }' > /etc/md5/layer7.md5
else
rm /tmp/l7marker.marks.tmp
fi
fi
}
insert_pf_loopback_rules()
{
config_name="firewall"
section_type="redirect"
#Need to always delete the old chains first.
delete_chain_from_table "nat" "pf_loopback_A"
delete_chain_from_table "filter" "pf_loopback_B"
delete_chain_from_table "nat" "pf_loopback_C"
define_wan_if
if [ -z "$wan_if" ] ; then return ; fi
wan_ip=$(uci -p /tmp/state get network.wan.ipaddr)
lan_mask=$(uci -p /tmp/state get network.lan.netmask)
if [ -n "$wan_ip" ] && [ -n "$lan_mask" ] ; then
iptables -t nat -N "pf_loopback_A"
iptables -t filter -N "pf_loopback_B"
iptables -t nat -N "pf_loopback_C"
iptables -t nat -I zone_lan_prerouting -d $wan_ip -j pf_loopback_A
iptables -t filter -I zone_lan_forward -j pf_loopback_B
iptables -t nat -I postrouting_rule -o br-lan -j pf_loopback_C
add_pf_loopback()
{
local vars="src dest proto src_dport dest_ip dest_port"
local all_defined="1"
for var in $vars ; do
config_get $var $1 $var
loaded=$(eval echo "\$$var")
#echo $var = $loaded
if [ -z "$loaded" ] && [ ! "$var" = "$src_dport" ] ; then
all_defined="0"
fi
done
if [ -z "$src_dport" ] ; then
src_dport=$dest_port
fi
sdp_dash=$src_dport
sdp_colon=$(echo $sdp_dash | sed 's/\-/:/g')
dp_dash=$dest_port
dp_colon=$(echo $dp_dash | sed 's/\-/:/g')
if [ "$all_defined" = "1" ] && [ "$src" = "wan" ] && [ "$dest" = "lan" ] ; then
iptables -t nat -A pf_loopback_A -p $proto --dport $sdp_colon -j DNAT --to-destination $dest_ip:$dp_dash
iptables -t filter -A pf_loopback_B -p $proto --dport $dp_colon -d $dest_ip -j ACCEPT
iptables -t nat -A pf_loopback_C -p $proto --dport $dp_colon -d $dest_ip -s $dest_ip/$lan_mask -j MASQUERADE
fi
}
config_load "$config_name"
config_foreach add_pf_loopback "$section_type"
fi
}
insert_dmz_rule()
{
local config_name="firewall"
local section_type="dmz"
#add rules for remote_accepts
parse_dmz_config()
{
vars="to_ip from"
for var in $vars ; do
config_get $var $1 $var
done
if [ -n "$from" ] ; then
from_if=$(uci -q -p /tmp/state get network.$from.ifname)
fi
# echo "from_if = $from_if"
if [ -n "$to_ip" ] && [ -n "$from" ] && [ -n "$from_if" ] ; then
iptables -t nat -A "zone_"$from"_prerouting" -i $from_if -j DNAT --to-destination $to_ip
# echo "iptables -t nat -A "prerouting_"$from -i $from_if -j DNAT --to-destination $to_ip"
iptables -t filter -I "zone_"$from"_forward" -d $to_ip -j ACCEPT
fi
}
config_load "$config_name"
config_foreach parse_dmz_config "$section_type"
}
insert_restriction_rules()
{
define_wan_if
if [ -z "$wan_if" ] ; then return ; fi
if [ -e /tmp/restriction_init.lock ] ; then return ; fi
touch /tmp/restriction_init.lock
egress_exists=$(iptables -t filter -L egress_restrictions 2>/dev/null)
ingress_exists=$(iptables -t filter -L ingress_restrictions 2>/dev/null)
if [ -n "$egress_exists" ] ; then
delete_chain_from_table filter egress_whitelist
delete_chain_from_table filter egress_restrictions
fi
if [ -n "$ingress_exists" ] ; then
delete_chain_from_table filter ingress_whitelist
delete_chain_from_table filter ingress_restrictions
fi
iptables -t filter -N egress_restrictions
iptables -t filter -N ingress_restrictions
iptables -t filter -N egress_whitelist
iptables -t filter -N ingress_whitelist
iptables -t filter -I FORWARD -o $wan_if -j egress_restrictions
iptables -t filter -I FORWARD -i $wan_if -j ingress_restrictions
iptables -t filter -I egress_restrictions -j egress_whitelist
iptables -t filter -I ingress_restrictions -j ingress_whitelist
package_name="firewall"
parse_rule_config()
{
section=$1
section_type=$(uci get "$package_name"."$section")
config_get "enabled" "$section" "enabled"
if [ -z "$enabled" ] ; then enabled="1" ; fi
if [ "$enabled" = "1" ] && ( [ "$section_type" = "restriction_rule" ] || [ "$section_type" = "whitelist_rule" ] ) ; then
#convert app_proto && not_app_proto to connmark here
config_get "app_proto" "$section" "app_proto"
config_get "not_app_proto" "$section" "not_app_proto"
if [ -n "$app_proto" ] ; then
app_proto_connmark=$(cat /etc/l7marker.marks 2>/dev/null | grep $app_proto | awk '{ print $2 ; }' )
app_proto_mask=$(cat /etc/l7marker.marks 2>/dev/null | grep $app_proto | awk '{ print $3 ; }' )
uci set "$package_name"."$section".connmark="$app_proto_connmark/$app_proto_mask"
fi
if [ -n "$not_app_proto" ] ; then
not_app_proto_connmark=$(cat /etc/l7marker.marks 2>/dev/null | grep "$not_app_proto" | awk '{ print $2 }')
not_app_proto_mask=$(cat /etc/l7marker.marks 2>/dev/null | grep "$not_app_proto" | awk '{ print $3 }')
uci set "$package_name"."$section".not_connmark="$not_app_proto_connmark/$not_app_proto_mask"
fi
table="filter"
chain="egress_restrictions"
ingress=""
target="REJECT"
config_get "is_ingress" "$section" "is_ingress"
if [ "$is_ingress" = "1" ] ; then
ingress=" -i "
if [ "$section_type" = "restriction_rule" ] ; then
chain="ingress_restrictions"
else
chain="ingress_whitelist"
fi
else
if [ "$section_type" = "restriction_rule" ] ; then
chain="egress_restrictions"
else
chain="egress_whitelist"
fi
fi
if [ "$section_type" = "whitelist_rule" ] ; then
target="ACCEPT"
fi
make_iptables_rules -p "$package_name" -s "$section" -t "$table" -c "$chain" -g "$target" $ingress
make_iptables_rules -p "$package_name" -s "$section" -t "$table" -c "$chain" -g "$target" $ingress -r
uci del "$package_name"."$section".connmark 2>/dev/null
uci del "$package_name"."$section".not_connmark 2>/dev/null
fi
}
config_load "$package_name"
config_foreach parse_rule_config "whitelist_rule"
config_foreach parse_rule_config "restriction_rule"
rm -rf /tmp/restriction_init.lock
}
initialize_quotas()
{
define_wan_if
if [ -z "$wan_if" ] ; then return ; fi
if [ -e /tmp/quota_init.lock ] ; then return ; fi
touch /tmp/quota_init.lock
lan_mask=$(uci -p /tmp/state get network.lan.netmask)
lan_ip=$(uci -p /tmp/state get network.lan.ipaddr)
full_qos_enabled=$(ls /etc/rc.d/*qos_gargoyle 2>/dev/null)
if [ -n "$full_qos_enabled" ] ; then
full_up=$(uci get qos_gargoyle.upload.total_bandwidth 2>/dev/null)
full_down=$(uci get qos_gargoyle.download.total_bandwidth 2>/dev/null)
if [ -z "$full_up" ] && [ -z "$full_down" ] ; then
full_qos_enabled=""
fi
fi
# restore_quotas does the hard work of building quota chains & rebuilding crontab file to do backups
#
# this initializes qos functions ONLY if we have quotas that
# have up and down speeds defined for when quota is exceeded
# and full qos is not enabled
if [ -z "$full_qos_enabled" ] ; then
restore_quotas -w $wan_if -d $death_mark -m $death_mask -s "$lan_ip/$lan_mask" -c "0 0,4,8,12,16,20 * * * /usr/bin/backup_quotas >/dev/null 2>&1"
initialize_quota_qos
else
restore_quotas -q -w $wan_if -d $death_mark -m $death_mask -s "$lan_ip/$lan_mask" -c "0 0,4,8,12,16,20 * * * /usr/bin/backup_quotas >/dev/null 2>&1"
cleanup_old_quota_qos
fi
#enable cron, but only restart cron if it is currently running
#since we initialize this before cron, this will
#make sure we don't start cron twice at boot
/etc/init.d/cron enable
cron_active=$(ps | grep "crond" | grep -v "grep" )
if [ -n "$cron_active" ] ; then
/etc/init.d/cron restart
fi
rm -rf /tmp/quota_init.lock
}
load_all_config_sections()
{
local config_name="$1"
local section_type="$2"
all_config_sections=""
section_order=""
config_cb()
{
if [ -n "$2" ] || [ -n "$1" ] ; then
if [ -n "$section_type" ] ; then
if [ "$1" = "$section_type" ] ; then
all_config_sections="$all_config_sections $2"
fi
else
all_config_sections="$all_config_sections $2"
fi
fi
}
config_load "$config_name"
echo "$all_config_sections"
}
cleanup_old_quota_qos()
{
for iface in $(tc qdisc show | awk '{print $5}' | sort -u ); do
tc qdisc del dev "$iface" root >/dev/null 2>&1
done
}
initialize_quota_qos()
{
cleanup_old_quota_qos
#speeds should be in kbyte/sec, units should NOT be present in config file (unit processing should be done by front-end)
quota_sections=$(load_all_config_sections "firewall" "quota")
upload_speeds=""
download_speeds=""
config_load "firewall"
for q in $quota_sections ; do
config_get "exceeded_up_speed" $q "exceeded_up_speed"
config_get "exceeded_down_speed" $q "exceeded_down_speed"
if [ -n "$exceeded_up_speed" ] && [ -n "$exceeded_down_speed" ] ; then
if [ $exceeded_up_speed -gt 0 ] && [ $exceeded_down_speed -gt 0 ] ; then
upload_speeds="$exceeded_up_speed $upload_speeds"
download_speeds="$exceeded_down_speed $download_speeds"
fi
fi
done
#echo "upload_speeds = $upload_speeds"
unique_up=$( printf "%d\n" $upload_speeds 2>/dev/null | sort -u -n)
unique_down=$( printf "%d\n" $download_speeds 2>/dev/null | sort -u -n)
#echo "unique_up = $unique_up"
num_up_bands=1
num_down_bands=1
if [ -n "$upload_speeds" ] ; then
num_up_bands=$((1 + $(printf "%d\n" $upload_speeds 2>/dev/null | sort -u -n | wc -l) ))
fi
if [ -n "$download_speeds" ] ; then
num_down_bands=$((1 + $(printf "%d\n" $download_speeds 2>/dev/null | sort -u -n | wc -l) ))
fi
#echo "num_up_bands=$num_up_bands"
#echo "num_down_bands=$num_down_bands"
if [ -n "$wan_if" ] && [ $num_up_bands -gt 1 ] && [ $num_down_bands -gt 1 ] ; then
insmod sch_prio >/dev/null 2>&1
insmod sch_tbf >/dev/null 2>&1
insmod cls_fw >/dev/null 2>&1
ifconfig imq0 down >/dev/null 2>&1
ifconfig imq1 down >/dev/null 2>&1
rmmod imq >/dev/null 2>&1
insmod imq numdevs=1 hook_chains="INPUT,FORWARD" hook_tables="mangle,mangle" >/dev/null 2>&1
ip link set imq0 up
#egress/upload
tc qdisc del dev $wan_if root >/dev/null 2>&1
tc qdisc add dev $wan_if handle 1:0 root prio bands $num_up_bands priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
cur_band=2
upload_shift=0
for rate_kb in $unique_up ; do
kbit=$(echo $((rate_kb*8))kbit)
mark=$(($cur_band << $upload_shift))
tc filter add dev $wan_if parent 1:0 prio $cur_band protocol ip handle $mark fw flowid 1:$cur_band
tc qdisc add dev $wan_if parent 1:$cur_band handle $cur_band: tbf rate $kbit burst $kbit limit $kbit
cur_band=$(($cur_band+1))
done
#ingress/download
tc qdisc del dev imq0 root >/dev/null 2>&1
tc qdisc add dev imq0 handle 1:0 root prio bands $num_down_bands priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
cur_band=2
download_shift=8
for rate_kb in $unique_down ; do
kbit=$(echo $((rate_kb*8))kbit)
mark=$(($cur_band << $download_shift))
tc filter add dev imq0 parent 1:0 prio $cur_band protocol ip handle $mark fw flowid 1:$cur_band
tc qdisc add dev imq0 parent 1:$cur_band handle $cur_band: tbf rate $kbit burst $kbit limit $kbit
cur_band=$(($cur_band+1))
done
iptables -t mangle -I ingress_quotas -i $wan_if -j IMQ --todev 0
#tc -s qdisc show dev $wan_if
#tc -s qdisc show dev imq0
fi
}
enforce_dhcp_assignments()
{
enforce_assignments=$(uci get firewall.@defaults[0].enforce_dhcp_assignments 2> /dev/null)
delete_chain_from_table "filter" "lease_mismatch_check"
local pairs1
local pairs2
local pairs
pairs1=""
pairs2=""
if [ -e /tmp/dhcp.leases ] ; then
pairs1=$(cat /tmp/dhcp.leases | sed '/^[ \t]*$/d' | awk ' { print $2"^"$3"\n" ; } ' )
fi
if [ -e /etc/ethers ] ; then
pairs2=$(cat /etc/ethers | sed '/^[ \t]*$/d' | awk ' { print $1"^"$2"\n" ; } ' )
fi
pairs=$( printf "$pairs1\n$pairs2\n" | sort | uniq )
if [ "$enforce_assignments" = "1" ] && [ -n "$pairs" ] ; then
iptables -t filter -N lease_mismatch_check
local p
for p in $pairs ; do
local mac
local ip
mac=$(echo $p | sed 's/\^.*$//g')
ip=$(echo $p | sed 's/^.*\^//g')
if [ -n "$ip" ] && [ -n "$mac" ] ; then
iptables -t filter -A lease_mismatch_check ! -s "$ip" -m mac --mac-source "$mac" -j REJECT
iptables -t filter -A lease_mismatch_check -s "$ip" -m mac ! --mac-source "$mac" -j REJECT
fi
done
iptables -t filter -I delegate_forward -j lease_mismatch_check
fi
}
force_router_dns()
{
force_router_dns=$(uci get firewall.@defaults[0].force_router_dns 2> /dev/null)
if [ "$force_router_dns" = "1" ] ; then
iptables -t nat -I zone_lan_prerouting -p tcp --dport 53 -j REDIRECT
iptables -t nat -I zone_lan_prerouting -p udp --dport 53 -j REDIRECT
fi
}
add_adsl_modem_routes()
{
wan_proto=$(uci -q get network.wan.proto)
if [ "$wan_proto" = "pppoe" ] ; then
wan_dev=$(uci -q get network.wan.ifname) #not really the interface, but the device
iptables -A postrouting_rule -t nat -o $wan_dev -j MASQUERADE
iptables -A forwarding_rule -o $wan_dev -j ACCEPT
/etc/ppp/ip-up.d/modemaccess.sh firewall $wan_dev
fi
}
initialize_firewall()
{
iptables -I zone_lan_forward -i br-lan -o br-lan -j ACCEPT
insert_remote_accept_rules
insert_dmz_rule
create_l7marker_chain
enforce_dhcp_assignments
force_router_dns
add_adsl_modem_routes
isolate_guest_networks
}
guest_mac_from_uci()
{
local is_guest_network
local macaddr
config_get is_guest_network "$1" is_guest_network
if [ "$is_guest_network" = "1" ] ; then
config_get macaddr "$1" macaddr
echo "$macaddr"
fi
}
get_guest_macs()
{
config_load "wireless"
config_foreach guest_mac_from_uci "wifi-iface"
}
isolate_guest_networks()
{
ebtables -t filter -F FORWARD
ebtables -t filter -F INPUT
local guest_macs=$( get_guest_macs )
if [ -n "$guest_macs" ] ; then
local lanifs=`brctl show br-lan 2>/dev/null | awk ' $NF !~ /interfaces/ { print $NF } '`
local lif
local lan_ip=$(uci -p /tmp/state get network.lan.ipaddr)
for lif in $lanifs ; do
for gmac in $guest_macs ; do
local is_guest=$(ifconfig "$lif" 2>/dev/null | grep -i "$gmac")
if [ -n "$is_guest" ] ; then
echo "$lif with mac $gmac is wireless guest"
#Allow access to WAN but not other LAN hosts for anyone on guest network
ebtables -t filter -A FORWARD -i "$lif" --logical-out br-lan -j DROP
#Only allow DHCP/DNS access to router for anyone on guest network
ebtables -t filter -A INPUT -i "$lif" -p ARP -j ACCEPT
ebtables -t filter -A INPUT -i "$lif" -p IPV4 --ip-protocol udp --ip-destination-port 53 -j ACCEPT
ebtables -t filter -A INPUT -i "$lif" -p IPV4 --ip-protocol udp --ip-destination-port 67 -j ACCEPT
ebtables -t filter -A INPUT -i "$lif" -p IPV4 --ip-destination $lan_ip -j DROP
fi
done
done
fi
}
ifup_firewall()
{
insert_restriction_rules
initialize_quotas
insert_pf_loopback_rules
}

View File

@ -1,49 +0,0 @@
#!/bin/sh
#This script allows access to the ADSL modem web interface when pppoe is used.
#For this to work configure your modem in bridge mode with DHCP enabled on the modem.
#This will cause the modem to dish an address to the router interface when requested below.
#
#Alternatively you can manually set the below variable ROUTER_IP with the IP address
#you want to use. Make sure the IP address is on the same network as the modem.
#ROUTER_IP=10.0.0.2
#Main case statement used only by udhcp which only calls with one of the
#following four key words in parameter 1.
case "$1" in
deconfig)
ifconfig "$interface" 0.0.0.0
exit 0
;;
renew)
ifconfig $interface $ip netmask ${subnet:-255.255.255.0} broadcast ${broadcast:-+}
exit 0
;;
bound)
ifconfig $interface $ip netmask ${subnet:-255.255.255.0} broadcast ${broadcast:-+}
exit 0
;;
nak)
exit 0
;;
leasefail)
exit 0
;;
esac
#if we get here then udhcp did not call us. Must be from pppd or /usr/lib/gargoyle_firewall_util
#configure the ethernet interface.
if [ -n "$ROUTER_IP" ] ; then
#In manual mode the user gave us an IP address for our interface
ifconfig $2 $ROUTER_IP netmask 255.255.255.0
else
#In auto mode we first check if we have an ip address already.
ROUTER_IP=$(ifconfig $2 | grep "inet addr:")
if [ -z "$ROUTER_IP" ]; then
#Dont have one so try an get one.
udhcpc -f -i $2 -n -q -s /etc/ppp/ip-up.d/modemaccess.sh
fi
fi
exit 0

View File

@ -1,21 +0,0 @@
#!/bin/sh /etc/rc.common
START=30
start()
{
/usr/bin/set_kernel_timezone
touch /etc/crontabs/root
if ! grep -q "set_kernel_timezone" /etc/crontabs/root; then
echo '0,1,11,21,31,41,51 * * * * /usr/bin/set_kernel_timezone >/dev/null 2>&1' >> /etc/crontabs/root
/etc/init.d/cron enable
#only restart cron if it is currently running
#since we initialize this before cron, this will
#make sure we don't start cron twice at boot
cron_active=$(ps | grep "crond" | grep -v "grep" )
if [ -n "$cron_active" ] ; then
/etc/init.d/cron restart
fi
fi
}

View File

@ -1,19 +0,0 @@
all: make_iptables_rules delete_chain_from_table backup_quotas restore_quotas print_quotas
print_quotas: print_quotas.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lericstools -luci -liptbwctl
restore_quotas: restore_quotas.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lericstools -luci -liptbwctl
backup_quotas: backup_quotas.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lericstools -luci -liptbwctl
delete_chain_from_table: delete_chain_from_table.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lericstools
make_iptables_rules: make_iptables_rules.c
$(CC) $(CFLAGS) $(LDFLAGS) make_iptables_rules.c -o make_iptables_rules -lericstools -luci -lm
clean:
rm -rf make_iptables_rules delete_chain_from_table print_quotas backup_quotas restore_quotas *.o *~ .*sw*

View File

@ -1,228 +0,0 @@
/* backup_quotas -- Used to backup quota data from iptables rules that use the "bandwidth" module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <erics_tools.h>
#include <uci.h>
#include <ipt_bwctl.h>
#define malloc safe_malloc
#define strdup safe_strdup
list* get_all_sections_of_type(struct uci_context *ctx, char* package, char* section_type);
void backup_quota(char* quota_id, char* quota_backup_dir);
char* get_uci_option(struct uci_context* ctx,char* package_name, char* section_name, char* option_name);
char* get_option_value_string(struct uci_option* uopt);
int main(void)
{
struct uci_context *ctx = uci_alloc_context();
list* quota_sections = get_all_sections_of_type(ctx, "firewall", "quota");
system("mkdir -p /usr/data/quotas");
unlock_bandwidth_semaphore_on_exit();
while(quota_sections->length > 0)
{
char* next_quota = shift_list(quota_sections);
char* ignore_backup = get_uci_option(ctx, "firewall", next_quota, "ignore_backup_at_next_restore");
int do_backup = 1;
if(ignore_backup != NULL)
{
if(strcmp(ignore_backup, "1") == 0)
{
do_backup = 0;
}
free(ignore_backup);
}
if(do_backup)
{
//do backup
/* base id for quota is the ip associated with it*/
char* backup_id = get_uci_option(ctx, "firewall", next_quota, "id");
char* ip = get_uci_option(ctx, "firewall", next_quota, "ip");
if(ip == NULL)
{
ip = strdup("ALL");
}
else if(strcmp(ip, "") == 0)
{
free(ip);
ip = strdup("ALL");
}
if(backup_id == NULL)
{
backup_id = strdup(ip);
}
else if(strcmp(backup_id, "") == 0)
{
free(backup_id);
backup_id = strdup(ip);
}
char* types[] = { "ingress_limit", "egress_limit", "combined_limit" };
char* postfixes[] = { "_ingress", "_egress", "_combined" };
int type_index;
for(type_index=0; type_index < 3; type_index++)
{
char* defined = get_uci_option(ctx, "firewall", next_quota, types[type_index]);
if(defined != NULL)
{
char* type_id = dynamic_strcat(2, backup_id, postfixes[type_index]);
backup_quota(type_id, "/usr/data/quotas" );
free(type_id);
free(defined);
}
}
free(backup_id);
free(ip);
}
free(next_quota);
}
unsigned long num;
destroy_list(quota_sections, DESTROY_MODE_FREE_VALUES, &num);
uci_free_context(ctx);
return 0;
}
list* get_all_sections_of_type(struct uci_context *ctx, char* package, char* section_type)
{
struct uci_package *p = NULL;
struct uci_element *e = NULL;
list* sections_of_type = initialize_list();
if(uci_load(ctx, package, &p) == UCI_OK)
{
uci_foreach_element( &p->sections, e)
{
struct uci_section *section = uci_to_section(e);
if(safe_strcmp(section->type, section_type) == 0)
{
push_list(sections_of_type, strdup(section->e.name));
}
}
}
return sections_of_type;
}
void backup_quota(char* id, char* quota_backup_dir)
{
/* if we ever bother to allow quotas to apply to subnets
* specified with '/', this may be necessary
*/
char* quota_file_name;
if(strstr(id, "/") != NULL)
{
char* quota_file_name = dynamic_replace(id, "/", "_");
}
else
{
quota_file_name = strdup(id);
}
char* quota_file_path = dynamic_strcat(3, quota_backup_dir, "/quota_", quota_file_name);
unsigned long num_ips;
ip_bw *ip_buf = NULL;
int query_succeeded = get_all_bandwidth_usage_for_rule_id(id, &num_ips, &ip_buf, 5000);
if(query_succeeded)
{
save_usage_to_file(ip_buf, num_ips, quota_file_path);
free(ip_buf);
}
free(quota_file_path);
free(quota_file_name);
}
char* get_uci_option(struct uci_context* ctx, char* package_name, char* section_name, char* option_name)
{
char* option_value = NULL;
struct uci_ptr ptr;
char* lookup_str = dynamic_strcat(5, package_name, ".", section_name, ".", option_name);
int ret_value = uci_lookup_ptr(ctx, &ptr, lookup_str, 1);
if(ret_value == UCI_OK)
{
if( !(ptr.flags & UCI_LOOKUP_COMPLETE))
{
ret_value = UCI_ERR_NOTFOUND;
}
else
{
struct uci_element *e = (struct uci_element*)ptr.o;
option_value = get_option_value_string(uci_to_option(e));
}
}
free(lookup_str);
return option_value;
}
// this function dynamically allocates memory for
// the option string, but since this program exits
// almost immediately (after printing variable info)
// the massive memory leak we're opening up shouldn't
// cause any problems. This is your reminder/warning
// that this might be an issue if you use this code to
// do anything fancy.
char* get_option_value_string(struct uci_option* uopt)
{
char* opt_str = NULL;
if(uopt->type == UCI_TYPE_STRING)
{
opt_str = strdup(uopt->v.string);
}
if(uopt->type == UCI_TYPE_LIST)
{
struct uci_element* e;
uci_foreach_element(&uopt->v.list, e)
{
if(opt_str == NULL)
{
opt_str = strdup(e->name);
}
else
{
char* tmp;
tmp = dynamic_strcat(3, opt_str, " ", e->name);
free(opt_str);
opt_str = tmp;
}
}
}
return opt_str;
}

View File

@ -1,79 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <erics_tools.h>
#define malloc safe_malloc
#define strdup safe_strdup
void free_split_pieces(char** split_pieces);
int main(int argc, char **argv)
{
char *table = argv[1];
char *delete_chain = argv[2];
if(argc != 3)
{
printf("USAGE: %s [TABLE] [CHAIN TO DELETE]\n\n", argv[0]);
return 0;
}
char *command = dynamic_strcat(3, "iptables -t ", table, " -L -n --line-numbers 2>/dev/null");
unsigned long num_lines = 0;
char** table_dump = get_shell_command_output_lines(command, &num_lines);
free(command);
unsigned long line_index;
char* current_chain = NULL;
list* delete_commands = initialize_list();
for(line_index=0; line_index < num_lines; line_index++)
{
char* line = table_dump[line_index];
unsigned long num_pieces = 0;
char whitespace[] = { '\t', ' ', '\r', '\n' };
char** line_pieces = split_on_separators(line, whitespace, 4, -1, 0, &num_pieces);
if(strcmp(line_pieces[0], "Chain") == 0)
{
if(current_chain != NULL) { free(current_chain); }
current_chain = strdup(line_pieces[1]);
}
else
{
unsigned long line_num;
int read = sscanf(line_pieces[0], "%ld", &line_num);
if(read > 0 && current_chain != NULL && num_pieces >1)
{
if(strcmp(line_pieces[1], delete_chain) == 0)
{
char* delete_command = dynamic_strcat(7, "iptables -t ", table, " -D ", current_chain, " ", line_pieces[0], " 2>/dev/null");
push_list(delete_commands, delete_command);
}
}
}
//free line_pieces
free_null_terminated_string_array(line_pieces);
}
free_null_terminated_string_array(table_dump);
/* final two commands to flush chain being deleted and whack it */
unshift_list(delete_commands, dynamic_strcat(5, "iptables -t ", table, " -F ", delete_chain, " 2>/dev/null"));
unshift_list(delete_commands, dynamic_strcat(5, "iptables -t ", table, " -X ", delete_chain, " 2>/dev/null"));
/* run delete commands */
while(delete_commands->length > 0)
{
char *next_command = (char*)pop_list(delete_commands);
char **out = get_shell_command_output_lines(next_command, &num_lines);
free_null_terminated_string_array(out);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,429 +0,0 @@
/* print_quotas -- Used to print quota data from iptables rules that use the "bandwidth" module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009-2010 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <erics_tools.h>
#include <uci.h>
#include <ipt_bwctl.h>
#define malloc safe_malloc
#define strdup safe_strdup
list* get_all_sections_of_type(struct uci_context *ctx, char* package, char* section_type);
void backup_quota(char* quota_id, char* quota_backup_dir);
char* get_uci_option(struct uci_context* ctx,char* package_name, char* section_name, char* option_name);
char* get_option_value_string(struct uci_option* uopt);
int main(void)
{
struct uci_context *ctx = uci_alloc_context();
list* quota_sections = get_all_sections_of_type(ctx, "firewall", "quota");
unlock_bandwidth_semaphore_on_exit();
/* for each ip have uint64_t[6], */
string_map *id_ip_to_bandwidth = initialize_string_map(1);
string_map *id_ip_to_percents = initialize_string_map(1);
string_map *id_ip_to_limits = initialize_string_map(1);
list *id_to_time = initialize_list();
while(quota_sections->length > 0)
{
char* next_quota = shift_list(quota_sections);
/* base id for quota is the ip associated with it*/
char *id = get_uci_option(ctx, "firewall", next_quota, "id");
char* ip = get_uci_option(ctx, "firewall", next_quota, "ip");
if(ip == NULL)
{
ip = strdup("ALL");
}
else if(strcmp(ip, "") == 0)
{
free(ip);
ip = strdup("ALL");
}
if(id == NULL)
{
id = strdup(ip);
}
else if(strcmp(id, "") == 0)
{
free(id);
id = strdup(ip);
}
string_map* ip_to_bandwidth = get_string_map_element(id_ip_to_bandwidth, id);
ip_to_bandwidth = ip_to_bandwidth == NULL ? initialize_string_map(1) : ip_to_bandwidth;
set_string_map_element(id_ip_to_bandwidth, id, ip_to_bandwidth);
string_map* ip_to_percents = get_string_map_element(id_ip_to_percents, id);
ip_to_percents = ip_to_percents == NULL ? initialize_string_map(1) : ip_to_percents;
set_string_map_element(id_ip_to_percents, id, ip_to_percents);
string_map* ip_to_limits = get_string_map_element(id_ip_to_limits, id);
ip_to_limits = ip_to_limits == NULL ? initialize_string_map(1) : ip_to_limits;
set_string_map_element(id_ip_to_limits, id, ip_to_limits);
char* offpeak_hours = get_uci_option(ctx, "firewall", next_quota, "offpeak_hours");
char* offpeak_weekdays = get_uci_option(ctx, "firewall", next_quota, "offpeak_weekdays");
char* offpeak_weekly_ranges = get_uci_option(ctx, "firewall", next_quota, "offpeak_weekly_ranges");
char* onpeak_hours = get_uci_option(ctx, "firewall", next_quota, "onpeak_hours");
char* onpeak_weekdays = get_uci_option(ctx, "firewall", next_quota, "onpeak_weekdays");
char* onpeak_weekly_ranges = get_uci_option(ctx, "firewall", next_quota, "onpeak_weekly_ranges");
if(offpeak_hours != NULL || offpeak_weekdays != NULL || offpeak_weekly_ranges != NULL || onpeak_hours != NULL || onpeak_weekdays != NULL || onpeak_weekly_ranges != NULL)
{
unsigned char is_off_peak = (offpeak_hours != NULL || offpeak_weekdays != NULL || offpeak_weekly_ranges != NULL) ? 1 : 0;
char* hours_var = is_off_peak ? offpeak_hours : onpeak_hours;
char* weekdays_var = is_off_peak ? offpeak_weekdays : onpeak_weekdays;
char* weekly_ranges_var = is_off_peak ? offpeak_weekly_ranges : onpeak_weekly_ranges;
char* active_var = is_off_peak ? strdup("except") : strdup("only");
if(weekly_ranges_var != NULL)
{
if(hours_var != NULL) { free(hours_var); hours_var=NULL; }
if(weekdays_var != NULL) { free(weekly_ranges_var); weekly_ranges_var=NULL; }
}
hours_var = hours_var == NULL ? strdup("") : hours_var;
weekdays_var = weekdays_var == NULL ? strdup("") : weekdays_var;
weekly_ranges_var = weekly_ranges_var == NULL ? strdup("") : weekly_ranges_var;
push_list(id_to_time, dynamic_strcat(11, "quotaTimes[\"", id, "\"] = [\"", hours_var, "\", \"", weekdays_var, "\", \"", weekly_ranges_var ,"\", \"", active_var, "\"];"));
free(hours_var);
free(weekdays_var);
free(weekly_ranges_var);
free(active_var);
}
else
{
push_list(id_to_time, dynamic_strcat(3, "quotaTimes[\"", id, "\"] = [\"\", \"\", \"\", \"always\"];"));
}
char* types[] = { "combined_limit", "ingress_limit", "egress_limit" };
char* postfixes[] = { "_combined", "_ingress", "_egress" };
int type_index;
for(type_index=0; type_index < 3; type_index++)
{
char* limit = get_uci_option(ctx, "firewall", next_quota, types[type_index]);
if(limit != NULL)
{
char* type_id = dynamic_strcat(2, id, postfixes[type_index]);
ip_bw* ip_buf;
unsigned long num_ips = 0;
int query_succeeded = get_all_bandwidth_usage_for_rule_id(type_id, &num_ips, &ip_buf, 5000);
if(query_succeeded && num_ips > 0)
{
unsigned long ip_index = 0;
for(ip_index = 0; ip_index < num_ips; ip_index++)
{
ip_bw next = ip_buf[ip_index];
char* next_ip = NULL;
if(next.ip == 0)
{
next_ip = strdup(ip);
}
else
{
struct in_addr addr;
addr.s_addr = next.ip;
next_ip = strdup(inet_ntoa(addr));
}
uint64_t *bw_list = get_string_map_element(ip_to_bandwidth,next_ip);
if(bw_list == NULL)
{
bw_list = (uint64_t*)malloc(sizeof(uint64_t)*6);
bw_list[0] = 0;
bw_list[1] = 0;
bw_list[2] = 0;
bw_list[3] = 0;
bw_list[4] = 0;
bw_list[5] = 0;
set_string_map_element(ip_to_bandwidth, next_ip, bw_list);
}
bw_list[type_index] = 1;
bw_list[type_index+3] = next.bw;
char bw_str[50];
sprintf(bw_str, "%lld", next.bw);
double bw_percent;
double bw_limit;
uint64_t bw_limit_64;
sscanf(bw_str, "%lf", &bw_percent);
sscanf(limit, "%lf", &bw_limit);
sscanf(limit, "%lld", &bw_limit_64);
if(bw_limit > 0)
{
bw_percent = (bw_percent*100.0)/bw_limit;
bw_percent = bw_percent > 100.0 ? 100.0 : bw_percent;
}
else
{
bw_percent = 100.0;
}
double* percent_list = get_string_map_element(ip_to_percents, next_ip);
if(percent_list == NULL)
{
percent_list = (double*)malloc(sizeof(double)*3);
percent_list[0] = -1;
percent_list[1] = -1;
percent_list[2] = -1;
set_string_map_element(ip_to_percents, next_ip, percent_list);
}
percent_list[type_index] = bw_percent;
uint64_t* limit_list = get_string_map_element(ip_to_limits, next_ip);
if(limit_list == NULL)
{
limit_list = (uint64_t*)malloc(sizeof(uint64_t)*3);
limit_list[0] = -1;
limit_list[1] = -1;
limit_list[2] = -1;
set_string_map_element(ip_to_limits, next_ip, limit_list);
}
limit_list[type_index] = bw_limit_64;
}
}
free(type_id);
free(limit);
}
}
free(id);
free(ip);
free(next_quota);
}
unsigned long num_ids;
char** id_list = (char**)get_string_map_keys(id_ip_to_bandwidth, &num_ids);
printf("var quotaIdList = [ ");
char print_comma[10] = "";
unsigned long id_index;
for(id_index=0; id_index < num_ids; id_index++)
{
printf("%s\"%s\"", print_comma, id_list[id_index]);
sprintf(print_comma, ", ");
}
printf(" ];\n");
printf("var quotaIpLists = [];\n");
for(id_index=0; id_index < num_ids; id_index++)
{
string_map* ip_to_bandwidth = get_string_map_element(id_ip_to_bandwidth, id_list[id_index]);
if(ip_to_bandwidth != NULL)
{
unsigned long num_ips = 0;
unsigned long ip_index = 0;
char** ip_list = (char**)get_string_map_keys(ip_to_bandwidth, &num_ips);
printf("quotaIpLists[\"%s\"] = [ ", id_list[id_index]);
sprintf(print_comma, "");
for(ip_index=0; ip_index < num_ips; ip_index++)
{
printf("%s\"%s\"", print_comma, ip_list[ip_index]);
sprintf(print_comma, ", ");
}
printf("];\n");
}
}
printf("var quotaTimes = new Array();\n");
printf("var quotaUsed = new Array();\n");
printf("var quotaLimits = new Array();\n");
printf("var quotaPercents = new Array();\n");
char* next_time = shift_list(id_to_time);
while(next_time != NULL)
{
printf("%s\n", next_time);
next_time = shift_list(id_to_time);
}
for(id_index=0; id_index < num_ids; id_index++)
{
char* next_id = id_list[id_index];
string_map* ip_to_bandwidth = get_string_map_element(id_ip_to_bandwidth, next_id);
string_map* ip_to_percents = get_string_map_element(id_ip_to_percents, next_id);
string_map* ip_to_limits = get_string_map_element(id_ip_to_limits, next_id);
printf("quotaUsed[ \"%s\" ] = [];\n", next_id);
printf("quotaPercents[ \"%s\" ] = [];\n", next_id);
printf("quotaLimits[ \"%s\" ] = [];\n", next_id);
if(ip_to_bandwidth != NULL)
{
unsigned long num_ips;
unsigned long ip_index = 0;
char** ip_list = (char**)get_string_map_keys(ip_to_bandwidth, &num_ips);
for(ip_index=0; ip_index < num_ips; ip_index++)
{
char* next_ip = ip_list[ip_index];
uint64_t* used = (uint64_t*)get_string_map_element(ip_to_bandwidth, next_ip);
double* percents = (double*)get_string_map_element(ip_to_percents, next_ip);
uint64_t* limits = (uint64_t*)get_string_map_element(ip_to_limits, next_ip);
if(used != NULL)
{
int type_index;
printf("quotaUsed[ \"%s\" ][ \"%s\" ] = [ ", next_id, next_ip);
sprintf(print_comma, "");
for(type_index=0; type_index < 3; type_index++)
{
if(!used[type_index])
{
printf("%s-1", print_comma);
}
else
{
printf("%s%lld", print_comma, (long long int)used[type_index+3]);
}
sprintf(print_comma, ", ");
}
printf(" ];\n");
printf("quotaPercents[ \"%s\" ][ \"%s\" ] = [ ", next_id, next_ip);
sprintf(print_comma, "");
for(type_index=0; type_index < 3; type_index++)
{
printf("%s%6.3lf", print_comma, percents[type_index]);
sprintf(print_comma, ", ");
}
printf(" ];\n");
printf("quotaLimits[ \"%s\" ][ \"%s\" ] = [ ", next_id, next_ip);
sprintf(print_comma, "");
for(type_index=0; type_index < 3; type_index++)
{
printf("%s%lld", print_comma,limits[type_index]);
sprintf(print_comma, ", ");
}
printf(" ];\n");
}
}
}
}
unsigned long num;
destroy_list(quota_sections, DESTROY_MODE_FREE_VALUES, &num);
uci_free_context(ctx);
return 0;
}
list* get_all_sections_of_type(struct uci_context *ctx, char* package, char* section_type)
{
struct uci_package *p = NULL;
struct uci_element *e = NULL;
list* sections_of_type = initialize_list();
if(uci_load(ctx, package, &p) == UCI_OK)
{
uci_foreach_element( &p->sections, e)
{
struct uci_section *section = uci_to_section(e);
if(safe_strcmp(section->type, section_type) == 0)
{
push_list(sections_of_type, strdup(section->e.name));
}
}
}
return sections_of_type;
}
char* get_uci_option(struct uci_context* ctx, char* package_name, char* section_name, char* option_name)
{
char* option_value = NULL;
struct uci_ptr ptr;
char* lookup_str = dynamic_strcat(5, package_name, ".", section_name, ".", option_name);
int ret_value = uci_lookup_ptr(ctx, &ptr, lookup_str, 1);
if(ret_value == UCI_OK)
{
if( !(ptr.flags & UCI_LOOKUP_COMPLETE))
{
ret_value = UCI_ERR_NOTFOUND;
}
else
{
struct uci_element *e = (struct uci_element*)ptr.o;
option_value = get_option_value_string(uci_to_option(e));
}
}
free(lookup_str);
return option_value;
}
// this function dynamically allocates memory for
// the option string, but since this program exits
// almost immediately (after printing variable info)
// the massive memory leak we're opening up shouldn't
// cause any problems. This is your reminder/warning
// that this might be an issue if you use this code to
// do anything fancy.
char* get_option_value_string(struct uci_option* uopt)
{
char* opt_str = NULL;
if(uopt->type == UCI_TYPE_STRING)
{
opt_str = strdup(uopt->v.string);
}
if(uopt->type == UCI_TYPE_LIST)
{
struct uci_element* e;
uci_foreach_element(&uopt->v.list, e)
{
if(opt_str == NULL)
{
opt_str = strdup(e->name);
}
else
{
char* tmp;
tmp = dynamic_strcat(3, opt_str, " ", e->name);
free(opt_str);
opt_str = tmp;
}
}
}
return opt_str;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +0,0 @@
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 9907 2007-12-25 01:59:55Z nbd $
include $(TOPDIR)/rules.mk
PKG_NAME:=libericstools
PKG_VERSION:=$(GARGOYLE_VERSION)
ifeq ($(GARGOYLE_VERSION),)
PKG_VERSION:=1.0.0
endif
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/libericstools
SECTION:=libs
CATEGORY:=Libraries
TITLE:=Erics Tools
URL:=http://www.gargoyle-router.com
MAINTAINER:=Eric Bishop <eric@gargoyle-router.com>
endef
define Package/libericstools/description
A bunch of routines/utilities written by Eric Bishop,
a library primarily used in Gargoyle Web Interface for OpenWrt
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)
endef
define Build/Configure
endef
define Build/InstallDev
mkdir -p $(STAGING_DIR)/usr/include/
$(CP) $(PKG_BUILD_DIR)/*.h $(STAGING_DIR)/usr/include/
mkdir -p $(STAGING_DIR)/usr/lib
$(CP) $(PKG_BUILD_DIR)/*.so* $(STAGING_DIR)/usr/lib/
endef
define Package/libericstools/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_BUILD_DIR)/*.so* $(1)/usr/lib/
endef
$(eval $(call BuildPackage,libericstools))

View File

@ -1,92 +0,0 @@
all: erics_tools
VERSION=1
ifeq ($(CC),)
CC=gcc
endif
ifeq ($(LD),)
LD=ld
endif
ifeq ($(AR),)
AR=ar
endif
ifeq ($(RANLIB),)
RANLIB=ranlib
endif
CFLAGS:=$(CFLAGS) -Os
WARNING_FLAGS=-Wall -Wstrict-prototypes -pedantic
MINIMAL_WARNING_FLAGS=-Wall -Wstrict-prototypes
OS=$(shell uname)
ifeq ($(OS),Darwin)
LINK=$(LD)
SHLIB_EXT=dylib
SHLIB_FLAGS=-dylib
SHLIB_FILE=libericstools.$(SHLIB_EXT).$(VERSION)
CFLAGS:=$(CFLAGS) -arch i386
else
LINK=$(CC)
SHLIB_EXT=so
SHLIB_FILE=libericstools.$(SHLIB_EXT).$(VERSION)
SHLIB_FLAGS=-shared -Wl,-soname,$(SHLIB_FILE)
endif
test_list_and_queue: test_list_and_queue.c libericstools.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
test_list_and_queue.o: test_list_and_queue.c
$(CC) $(CFLAGS) $(MINIMAL_WARNING_FLAGS) -o $@ -c $^
test_string: test_string.o libericstools.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
test_string.o: test_string.c
$(CC) $(CFLAGS) $(MINIMAL_WARNING_FLAGS) -c $^ -o $@
test_map: test_map.o libericstools.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
test_map.o: test_map.c
$(CC) $(CFLAGS) $(MINIMAL_WARNING_FLAGS) -c $^ -o $@
all: erics_tools
erics_tools: libericstools.$(SHLIB_EXT) libericstools.a
libericstools.a: list_static.o priority_queue_static.o tree_map_static.o string_util_static.o file_util_static.o safe_malloc_static.o
if [ -e $@ ] ; then rm $@ ; fi
$(AR) rc $@ $^
$(RANLIB) $@
libericstools.$(SHLIB_EXT) : list_dyn.o priority_queue_dyn.o tree_map_dyn.o string_util_dyn.o file_util_dyn.o safe_malloc_dyn.o
if [ -e libericstools.$(SHLIB_EXT) ] ; then rm libericstools.$(SHLIB_EXT)* ; fi
$(LINK) $(LDFLAGS) $(SHLIB_FLAGS) -o $(SHLIB_FILE) $^ -lc
ln -s $(SHLIB_FILE) libericstools.$(SHLIB_EXT)
%_dyn.o: %.c
$(CC) $(CFLAGS) -fPIC $(WARNING_FLAGS) -o $@ -c $^
%_static.o: %.c
$(CC) $(CFLAGS) $(WARNING_FLAGS) -o $@ -c $^
clean:
rm -rf *.a *.o .*sw* *~ test_map test_string test_list_and_queue
if [ "$(SHLIB_EXT)" != "" ] ; then rm -rf *.$(SHLIB_EXT)* ; fi
install:
cp *.h /usr/include
cp *.$(SHLIB_EXT)* /usr/lib

View File

@ -1,309 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work 'as-is' we provide.
* No warranty, express or implied.
* We've done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#ifndef ERICS_TOOLS_H
#define ERICS_TOOLS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <regex.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#ifndef stricmp
#define stricmp strcasecmp
#endif
/* tree_map structs / prototypes */
typedef struct long_tree_map_node
{
unsigned long key;
void* value;
signed char balance;
struct long_tree_map_node* left;
struct long_tree_map_node* right;
} long_map_node;
typedef struct
{
long_map_node* root;
unsigned long num_elements;
}long_map;
typedef struct
{
long_map lm;
unsigned char store_keys;
unsigned long num_elements;
}string_map;
/* long map functions */
extern long_map* initialize_long_map(void);
extern void* get_long_map_element(long_map* map, unsigned long key);
void* get_smallest_long_map_element(long_map* map, unsigned long* smallest_key);
void* get_largest_long_map_element(long_map* map, unsigned long* largest_key);
void* remove_smallest_long_map_element(long_map* map, unsigned long* smallest_key);
void* remove_largest_long_map_element(long_map* map, unsigned long* largest_key);
extern void* set_long_map_element(long_map* map, unsigned long key, void* value);
extern void* remove_long_map_element(long_map* map, unsigned long key);
extern unsigned long* get_sorted_long_map_keys(long_map* map, unsigned long* num_keys_returned);
extern void** get_sorted_long_map_values(long_map* map, unsigned long* num_values_returned);
extern void** destroy_long_map(long_map* map, int destruction_type, unsigned long* num_destroyed);
extern void apply_to_every_long_map_value(long_map* map, void (*apply_func)(unsigned long key, void* value));
/* string map functions */
extern string_map* initialize_string_map(unsigned char store_keys);
extern void* get_string_map_element(string_map* map, const char* key);
extern void* set_string_map_element(string_map* map, const char* key, void* value);
extern void* remove_string_map_element(string_map* map, const char* key);
extern char** get_string_map_keys(string_map* map, unsigned long* num_keys_returned);
extern void** get_string_map_values(string_map* map, unsigned long* num_values_returned);
extern void** destroy_string_map(string_map* map, int destruction_type, unsigned long* num_destroyed);
extern void apply_to_every_string_map_value(string_map* map, void (*apply_func)(char* key, void* value));
/*
* three different ways to deal with values when data structure is destroyed
*/
#define DESTROY_MODE_RETURN_VALUES 20
#define DESTROY_MODE_FREE_VALUES 21
#define DESTROY_MODE_IGNORE_VALUES 22
/*
* for convenience & backwards compatibility alias _string_map_ functions to
* _map_ functions since string map is used more often than long map
*/
#define initialize_map initialize_string_map
#define set_map_element set_string_map_element
#define get_map_element get_string_map_element
#define remove_map_element remove_string_map_element
#define get_map_keys get_string_map_keys
#define get_map_values get_string_map_values
#define destroy_map destroy_string_map
/* list structs / prototypes */
typedef struct list_node_struct
{
struct list_node_struct* next;
struct list_node_struct* previous;
void* value;
} list_node;
typedef struct list_struct
{
long length;
list_node* head;
list_node* tail;
}list;
extern list* initialize_list(void); /* O(1) */
extern void* shift_list(list* l); /* O(1) */
extern void unshift_list(list* l, void* value); /* O(1) */
extern void* pop_list(list* l); /* O(1) */
extern void push_list(list*l, void* value); /* O(1) */
extern void** destroy_list(list* l, int destruction_type, unsigned long* num_destroyed); /* O(n) */
extern void* list_element_at(list* l, unsigned long index); /* O(n) */
extern void** get_list_values(list* l, unsigned long* num_values_returned); /* O(n) */
/* The idea behind the remove_internal_node function and
* the other functions below that perform list operations on
* list_node pointers instead of values is as follows:
*
* It is O(n) to remove arbitrary node from list. BUT, if
* we have a pointer to that node already it is O(1). So,
* provide functions to manipulate list with list_node pointers
* instead of values & a function to remove an internal node
* given a pointer to that node. This means we can have
* access to internal nodes & use another
* data structure to store internal nodes and delete in O(1)
*/
extern void remove_internal_list_node(list*l, list_node* internal); /* O(1) */
extern list_node* create_list_node(void* value); /* O(1) */
extern void* free_list_node(list_node* delete_node); /* O(1) */
extern list_node* shift_list_node(list* l); /* O(1) */
extern void unshift_list_node(list* l, list_node* new_node); /* O(1) */
extern list_node* pop_list_node(list* l); /* O(1) */
extern void push_list_node(list*l, list_node* new_node); /* O(1) */
/* priority_queue structs / prototypes */
typedef struct priority_queue_node_struct
{
unsigned long priority;
char* id;
void* value;
} priority_queue_node;
typedef struct priority_queue_struct
{
long_map* priorities;
string_map* ids;
priority_queue_node* first;
long length;
} priority_queue;
extern priority_queue* initialize_priority_queue(void);
extern priority_queue_node* create_priority_node(unsigned long priority, char* id, void* value);
extern void* free_priority_queue_node(priority_queue_node* pn);
extern void push_priority_queue(priority_queue* pq, unsigned long priority, char* id, void * value);
extern void* shift_priority_queue(priority_queue* pq, unsigned long* priority, char** id);
extern void* peek_priority_queue(priority_queue* pq, unsigned long* priority, char** id, int dynamic_alloc_id);
extern void* get_priority_queue_element_with_id(priority_queue* pq, char* id, long* priority);
extern void* remove_priority_queue_element_with_id(priority_queue* pq, char* id, long* priority);
extern void push_priority_queue_node(priority_queue* pq, priority_queue_node* pn);
extern priority_queue_node* shift_priority_queue_node(priority_queue* pq);
extern priority_queue_node* get_priority_queue_node_with_id(priority_queue* pq, char* id);
extern priority_queue_node* remove_priority_queue_node_with_id(priority_queue* pq, char* id);
extern void set_priority_for_id_in_priority_queue(priority_queue* pq, char* id, unsigned long priority);
extern priority_queue_node* peek_priority_queue_node(priority_queue* pq);
extern void** destroy_priority_queue(priority_queue* pq, int destroy_mode, unsigned long* num_destroyed);
/* string_util structs / prototypes */
typedef struct
{
char* str;
int terminator;
} dyn_read_t;
/* non-dynamic functions */
extern char* replace_prefix(char* original, char* old_prefix, char* new_prefix);
extern char* trim_flanking_whitespace(char* str);
extern int safe_strcmp(const char* str1, const char* str2);
extern void to_lowercase(char* str);
extern void to_uppercase(char* str);
/* dynamic functions (e.g. new memory is allocated, return values must be freed) */
int free_null_terminated_string_array(char** strs);
char** copy_null_terminated_string_array(char** original);
extern char* dynamic_strcat(int num_strs, ...);
extern char* dcat_and_free(char** one, char** two, int free1, int free2);
extern char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long* num_pieces); /*if max_pieces < 0, it is ignored */
extern char* join_strs(char* separator, char** parts, int max_parts, int free_parts, int free_parts_array); /*if max_parts < 0, it is ignored*/
extern char* dynamic_replace(char* template_str, char* old_str, char* new_str);
int convert_to_regex(char* str, regex_t* p);
/* functions to dynamically read files */
extern dyn_read_t dynamic_read(FILE* open_file, char* terminators, int num_terminators, unsigned long* read_length);
extern int dyn_read_line(FILE* open_file, char** dest, unsigned long* read_len);
extern unsigned char* read_entire_file(FILE* in, unsigned long read_block_size, unsigned long* read_length);
/* run a command and get (dynamically allocated) output lines */
extern char** get_shell_command_output_lines(char* command, unsigned long* num_lines);
/* comparison functions for qsort */
extern int sort_string_cmp(const void *a, const void *b);
extern int sort_string_icmp(const void *a, const void *b);
/* wrappers for qsort calls */
extern void do_str_sort(char** string_arr, unsigned long string_arr_len);
extern void do_istr_sort(char** string_arr, unsigned long string_arr_len);
/* safe malloc & strdup functions used by all others (actually aliased to malloc / strdup and used) */
extern void* safe_malloc(size_t size);
extern char* safe_strdup(const char* str);
/* utility functions to free memory */
extern void free_if_not_null(void* p);
extern void free_and_set_null(void** p);
/* other file utils */
extern int mkdir_p(const char* path, mode_t mode); /* returns 0 on success, 1 on error */
extern void rm_r(const char* path);
extern int create_tmp_dir(const char* tmp_root, char** tmp_dir); /* returns 0 on success, 1 on error */
#define PATH_DOES_NOT_EXIST 0
#define PATH_IS_REGULAR_FILE 1
#define PATH_IS_DIRECTORY 2
#define PATH_IS_SYMLINK 3
#define PATH_IS_OTHER 4
/*
returns:
PATH_DOES_NOT_EXIST (0) if path doesn't exist
PATH_IS_REGULAR_FILE (1) if path is regular file
PATH_IS_DIRECTORY (2) if path is directory
PATH_IS_SYMLINK (3) if path is symbolic link
PATH_IS_OTHER (4) if path exists and is something else
*/
extern int path_exists(const char* path);
extern char** get_file_lines(char* file_path, unsigned long* lines_read);
#endif /* ERICS_TOOLS_H */

View File

@ -1,195 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work as-is we provide.
* No warranty, express or implied.
* Weve done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
#define malloc safe_malloc
#define strdup safe_strdup
static int __srand_called = 0;
int create_tmp_dir(const char* tmp_root, char** tmp_dir)
{
if(! __srand_called)
{
srand(time(NULL));
__srand_called = 1;
}
sprintf((*tmp_dir), "%s/tmp_%d", tmp_root, rand());
return (mkdir_p(*tmp_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ));
}
/*
returns:
PATH_DOES_NOT_EXIST (0) if path doesn't exist
PATH_IS_REGULAR_FILE (1) if path is regular file
PATH_IS_DIRECTORY (2) if path is directory
PATH_IS_SYMLINK (3) if path is symbolic link
PATH_IS_OTHER (4) if path exists and is something else
*/
int path_exists(const char* path)
{
struct stat fs;
int exists = lstat(path,&fs) >= 0 ? PATH_IS_OTHER : PATH_DOES_NOT_EXIST;
if(exists > 0)
{
exists = S_ISREG(fs.st_mode) ? PATH_IS_REGULAR_FILE : exists;
exists = S_ISDIR(fs.st_mode) ? PATH_IS_DIRECTORY : exists;
exists = S_ISLNK(fs.st_mode) ? PATH_IS_SYMLINK : exists;
}
return exists;
}
int mkdir_p(const char* path, mode_t mode)
{
int err=0;
struct stat fs;
char* dup_path = strdup(path);
char* sep = strchr(dup_path, '/');
sep = (sep == dup_path) ? strchr(sep+1, '/') : sep;
while(sep != NULL && err == 0)
{
sep[0] = '\0';
if(stat(dup_path,&fs) >= 0)
{
if(!S_ISDIR(fs.st_mode))
{
err = 1;
}
}
else
{
mkdir(dup_path, mode);
}
err =1;
if(stat(dup_path,&fs) >= 0)
{
err = S_ISDIR(fs.st_mode) ? 0 : 1;
}
sep[0] = '/';
sep = strchr(sep+1, '/');
}
if(err == 0)
{
if(stat(dup_path,&fs) >= 0)
{
if(!S_ISDIR(fs.st_mode))
{
err = 1;
}
}
else
{
mkdir(dup_path, mode);
}
err =1;
if(stat(dup_path,&fs) >= 0)
{
err = S_ISDIR(fs.st_mode) ? 0 : 1;
}
}
free(dup_path);
return err;
}
void rm_r(const char* path)
{
struct stat fs;
if(lstat(path,&fs) >= 0)
{
if(S_ISDIR (fs.st_mode))
{
/* remove directory recursively */
struct dirent **entries;
int num_entry_paths;
int entry_path_index;
num_entry_paths = scandir(path, &entries, 0, alphasort);
for(entry_path_index=0; entry_path_index < num_entry_paths; entry_path_index++)
{
struct dirent *dentry = entries[entry_path_index];
if(strcmp(dentry->d_name, "..") != 0 && strcmp(dentry->d_name, ".") != 0)
{
char* entry_path = (char*)malloc(strlen(path) + strlen(dentry->d_name) + 2);
sprintf(entry_path,"%s/%s", path, dentry->d_name);
/* recurse */
rm_r(entry_path);
free(entry_path);
}
}
remove(path);
}
else
{
/* remove regular file, no need to recurse */
remove(path);
}
}
}
char** get_file_lines(char* file_path, unsigned long* lines_read)
{
char** result = NULL;
int path_type = path_exists(file_path);
*lines_read = 0;
if(path_type != PATH_DOES_NOT_EXIST && path_type != PATH_IS_DIRECTORY) /* exists and is not directory */
{
FILE* read_file = fopen(file_path, "r");
unsigned char* file_data = NULL;
if(read_file != NULL)
{
unsigned long file_length;
file_data = read_entire_file(read_file, 1024, &file_length);
fclose(read_file);
}
if(file_data != NULL)
{
char line_seps[] = {'\r', '\n'};
result = split_on_separators((char*)file_data, line_seps , 2, -1, 0, lines_read);
free(file_data);
}
}
return result;
}

View File

@ -1,280 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work as-is we provide.
* No warranty, express or implied.
* Weve done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
#define malloc safe_malloc
#define strdup safe_strdup
list* initialize_list()
{
list* l = (list*)malloc(sizeof(list));
l->length = 0;
l->head = NULL;
l->tail = NULL;
return l;
}
list_node* create_list_node(void* value)
{
list_node* new_node = (list_node*)malloc(sizeof(list_node));
new_node->value = value;
new_node->previous = NULL;
new_node->next = NULL;
return new_node;
}
void* free_list_node(list_node* delete_node)
{
void* value = NULL;
if(delete_node != NULL)
{
value = delete_node->value;
free(delete_node);
}
return value;
}
list_node* shift_list_node(list* l)
{
list_node* return_node = NULL;
if(l != NULL)
{
if(l->head != NULL)
{
return_node = l->head;
l->head = l->head->next;
if(l->head != NULL) { l->head->previous = NULL; }
l->tail = l->tail == return_node ? NULL : l->tail;
l->length = l->length -1;
return_node->previous = NULL;
return_node->next = NULL;
}
}
return return_node;
}
void unshift_list_node(list* l, list_node* new_node)
{
if(l != NULL && new_node != NULL)
{
new_node->previous = NULL;
if(l->head == NULL) /* list is empty */
{
new_node->next = NULL;
l->tail = new_node;
}
else
{
new_node->next = l->head;
l->head->previous = new_node;
}
l->head = new_node;
l->length = l->length +1;
}
}
list_node* pop_list_node(list* l)
{
list_node* return_node = NULL;
if(l != NULL)
{
if(l->tail != NULL)
{
return_node = l->tail;
l->tail = l->tail->previous;
if(l->tail != NULL) { l->tail->next = NULL; }
l->head = l->head == return_node ? NULL : l->head;
l->length = l->length -1;
return_node->previous = NULL;
return_node->next = NULL;
}
}
return return_node;
}
void push_list_node(list* l, list_node* new_node)
{
if(l != NULL && new_node != NULL)
{
new_node->next = NULL;
if(l->tail == NULL) /* list is empty */
{
new_node->previous = NULL;
l->head = new_node;
}
else
{
new_node->previous = l->tail;
l->tail->next = new_node;
}
l->tail = new_node;
l->length = l->length +1;
}
}
void* shift_list(list* l)
{
return free_list_node ( shift_list_node(l) );
}
void unshift_list(list* l, void* value)
{
list_node* new_node = create_list_node(value);
unshift_list_node(l, new_node);
}
void* pop_list(list* l)
{
return free_list_node ( pop_list_node(l) );
}
void push_list(list*l, void* value)
{
list_node* new_node = create_list_node(value);
push_list_node(l, new_node);
}
void remove_internal_list_node(list* l, list_node* internal)
{
/* note we assume internal is in l, otherwise everything gets FUBAR! */
if(l != NULL && internal != NULL)
{
list_node* next = internal->next;
list_node* previous = internal->previous;
if(previous == NULL) /* internal is head */
{
l->head = next;
if(l->head != NULL) { l->head->previous = NULL; }
}
if(next == NULL) /* internal is tail */
{
l->tail = previous;
if(l->tail != NULL) { l->tail->next = NULL; }
}
if(previous != NULL && next != NULL)
{
previous->next = next;
next->previous = previous;
}
internal->next = NULL;
internal->previous = NULL;
l->length = l->length - 1;
}
}
void** destroy_list(list* l, int destruction_type, unsigned long* num_values)
{
void** values = NULL;
unsigned long value_index = 0;
if(l != NULL)
{
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
values = (void**)malloc((1+l->length)*sizeof(void*));
}
for(value_index=0; l->length > 0; value_index++)
{
void* value = shift_list(l);
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
values[value_index] = value;
}
else if(destruction_type == DESTROY_MODE_FREE_VALUES)
{
free(value);
}
}
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
values[value_index] = NULL;
}
free(l);
}
*num_values = value_index;
return values;
}
void* list_element_at(list* l, unsigned long index)
{
void* return_value = NULL;
if(l != NULL)
{
unsigned long current_index = index - (unsigned long)((l->length)/2) > 0 ? l->length -1 : 0;
list_node* current_node = current_index == 0 ? l->head : l->tail;
while(current_index != index && current_node != NULL)
{
current_node = current_index > index ? current_node->previous : current_node->next;
current_index = current_index > index ? current_index -1 : current_index + 1;
}
if(current_node != NULL)
{
return_value = current_node->value;
}
}
return return_value;
}
void** get_list_values(list* l, unsigned long* num_values) /* returns null terminated array */
{
void** values = NULL;
unsigned long value_index = 0;
if(l != NULL)
{
list_node* current_node = l->head;
values = (void**)malloc((1+l->length)*sizeof(void*));
for(value_index = 0; value_index < l->length; value_index++)
{
values[value_index] = current_node->value;
current_node = current_node->next;
}
values[value_index] = NULL;
}
*num_values = value_index;
return values;
}

View File

@ -1,360 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work as-is we provide.
* No warranty, express or implied.
* Weve done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
#define malloc safe_malloc
#define strdup safe_strdup
typedef struct id_map_node_struct
{
list* id_list;
list_node* id_node;
} id_map_node;
priority_queue* initialize_priority_queue(void)
{
priority_queue* pq = (priority_queue*)malloc(sizeof(priority_queue));
pq->priorities = initialize_long_map();
pq->ids = initialize_string_map(0);
pq->first = NULL;
pq->length = 0;
return pq;
}
priority_queue_node* create_priority_node(unsigned long priority, char* id, void* value)
{
priority_queue_node* pn = (priority_queue_node*)malloc(sizeof(priority_queue_node));
pn->priority = priority;
pn->id = strdup(id);
pn->value = value;
return pn;
}
void* free_priority_queue_node(priority_queue_node* pn)
{
void *return_value = NULL;
if(pn != NULL)
{
return_value = pn->value;
free(pn->id);
free(pn);
}
return return_value;
}
void push_priority_queue(priority_queue* pq, unsigned long priority, char* id, void * value)
{
if(pq != NULL && id != NULL)
{
priority_queue_node* pn = create_priority_node(priority, id, value);
push_priority_queue_node(pq, pn);
}
}
/* note id is ALWAYS dynamically allocated, need to free */
void* shift_priority_queue(priority_queue* pq, unsigned long* priority, char** id)
{
void* return_value = NULL;
priority_queue_node* pn = shift_priority_queue_node(pq);
if(pn != NULL)
{
*priority = pn->priority;
*id = strdup(pn->id);
return_value = free_priority_queue_node(pn);
}
return return_value;
}
/* last param specified whether to dynamicall allocate id (otherwise pointer to id in priority_queue_node) */
void* peek_priority_queue(priority_queue* pq, unsigned long* priority, char** id, int dynamic_alloc_id)
{
void* return_value = NULL;
*priority = 0;
*id = NULL;
if(pq != NULL)
{
if(pq->first != NULL)
{
return_value = pq->first->value;
*priority = pq->first->priority;
if(dynamic_alloc_id)
{
*id = strdup(pq->first->id);
}
else
{
*id = pq->first->id;
}
}
}
return return_value;
}
void* get_priority_queue_element_with_id(priority_queue* pq, char* id, long* priority)
{
void* return_value = NULL;
priority_queue_node* pn = get_priority_queue_node_with_id(pq, id);
if(pn != NULL)
{
*priority = pn->priority;
return_value = free_priority_queue_node(pn);
}
else
{
*priority = 0;
}
return return_value;
}
void* remove_priority_queue_element_with_id(priority_queue* pq, char* id, long* priority)
{
void* return_value = NULL;
priority_queue_node* pn = remove_priority_queue_node_with_id(pq, id);
if(pn != NULL)
{
*priority = pn->priority;
return_value = free_priority_queue_node(pn);
}
else
{
*priority = 0;
}
return return_value;
}
void push_priority_queue_node(priority_queue* pq, priority_queue_node* pn)
{
if(pq != NULL && pn != NULL)
{
/* assume that most of the time we won't have collisions */
list_node* lpn = create_list_node(pn);
list* new_list = initialize_list();
list* old_list;
id_map_node* idn;
push_list_node(new_list, lpn);
old_list = (list*)set_long_map_element(pq->priorities, pn->priority, new_list);
if(old_list != NULL)
{
push_list_node(old_list, lpn);
set_long_map_element(pq->priorities, pn->priority, old_list);
free(new_list);
new_list = old_list;
}
/* update first */
if(pq->first == NULL)
{
pq->first = pn;
}
else if(pn->priority < pq->first->priority)
{
pq->first = pn;
}
/* save id */
idn = (id_map_node*)malloc(sizeof(id_map_node));
idn->id_list = new_list;
idn->id_node = lpn;
set_string_map_element(pq->ids, pn->id, idn);
pq->length = pq->length + 1;;
}
}
priority_queue_node* shift_priority_queue_node(priority_queue* pq)
{
priority_queue_node* return_node = NULL;
if(pq != NULL)
{
if(pq->first != NULL)
{
list* next_list = (list*)remove_long_map_element(pq->priorities, pq->first->priority);
list* next_first_list = NULL;
list_node* smallest_list_node = shift_list_node(next_list);
id_map_node* idn;
if(next_list->length == 0)
{
unsigned long tmp;
destroy_list(next_list, DESTROY_MODE_IGNORE_VALUES, &tmp);
next_first_list = (list*)get_smallest_long_map_element(pq->priorities, &tmp);
}
else
{
set_long_map_element(pq->priorities, pq->first->priority, next_list);
next_first_list = next_list;
}
return_node = free_list_node(smallest_list_node);
idn = (id_map_node*)remove_string_map_element(pq->ids, return_node->id);
free(idn);
if(next_first_list != NULL)
{
list_node* next_first_node = shift_list_node(next_first_list);
pq->first = (priority_queue_node*)next_first_node->value;
unshift_list_node(next_first_list, next_first_node);
}
else
{
pq->first = NULL;
}
pq->length = pq->length -1;
}
}
return return_node;
}
priority_queue_node* get_priority_queue_node_with_id(priority_queue* pq, char* id)
{
priority_queue_node* return_node = NULL;
if(pq != NULL && id != NULL)
{
id_map_node* idn = (id_map_node*)get_string_map_element(pq->ids, id);
if(idn != NULL)
{
return_node = (priority_queue_node*)idn->id_node->value;
}
}
return return_node;
}
priority_queue_node* remove_priority_queue_node_with_id(priority_queue* pq, char* id)
{
priority_queue_node* return_node = NULL;
if(pq != NULL && id != NULL)
{
id_map_node* idn = (id_map_node*)remove_string_map_element(pq->ids, id);
if(idn != NULL)
{
/* remove relevant node from list */
remove_internal_list_node(idn->id_list, idn->id_node);
return_node = free_list_node(idn->id_node);
/* if list is empty remove it from priority map */
if(idn->id_list->length == 0)
{
unsigned long tmp;
remove_long_map_element(pq->priorities, return_node->priority);
destroy_list(idn->id_list, DESTROY_MODE_IGNORE_VALUES, &tmp);
}
free(idn);
/* if we're removing first node, reset it */
if(return_node == pq->first)
{
unsigned long tmp;
list* next_first_list = (list*)get_smallest_long_map_element(pq->priorities, &tmp);
if(next_first_list != NULL)
{
list_node* next_first_node = shift_list_node(next_first_list);
pq->first = (priority_queue_node*)next_first_node->value;
unshift_list_node(next_first_list, next_first_node);
}
else
{
pq->first = NULL;
}
}
pq->length = pq->length -1;
}
}
return return_node;
}
void set_priority_for_id_in_priority_queue(priority_queue* pq, char* id, unsigned long priority)
{
if(pq != NULL && id != NULL)
{
priority_queue_node* id_pq_node = remove_priority_queue_node_with_id(pq, id);
id_pq_node->priority = priority;
push_priority_queue_node(pq, id_pq_node);
}
}
priority_queue_node* peek_priority_queue_node(priority_queue* pq)
{
return pq->first;
}
void** destroy_priority_queue(priority_queue* pq, int destroy_mode, unsigned long* num_elements_destroyed)
{
void** values = NULL;
unsigned long tmp;
*num_elements_destroyed = 0;
if(pq != NULL)
{
if(destroy_mode == DESTROY_MODE_RETURN_VALUES)
{
values = (void**)malloc((pq->length+1)*sizeof(void*));
}
while(pq->length > 0)
{
priority_queue_node* pqn = shift_priority_queue_node(pq);
void* next_value = free_priority_queue_node(pqn);
if(destroy_mode == DESTROY_MODE_RETURN_VALUES)
{
values[*num_elements_destroyed] = next_value;
}
else if(destroy_mode == DESTROY_MODE_FREE_VALUES)
{
free(next_value);
}
*num_elements_destroyed = *num_elements_destroyed + 1;
}
if(destroy_mode == DESTROY_MODE_RETURN_VALUES)
{
values[*num_elements_destroyed] = NULL;
}
destroy_long_map(pq->priorities, DESTROY_MODE_FREE_VALUES, &tmp);
destroy_string_map(pq->ids, DESTROY_MODE_FREE_VALUES, &tmp);
free(pq);
}
return values;
}

View File

@ -1,80 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work as-is we provide.
* No warranty, express or implied.
* Weve done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
void *safe_malloc(size_t size)
{
void* val = malloc(size);
if(val == NULL)
{
fprintf(stderr, "ERROR: MALLOC FAILURE!\n");
exit(1);
}
return val;
}
char* safe_strdup(const char* str)
{
char* new_str = NULL;
if(str != NULL)
{
new_str = strdup(str);
if(new_str == NULL)
{
fprintf(stderr, "ERROR: MALLOC FAILURE!\n");
exit(1);
}
}
return new_str;
}
void free_if_not_null(void* p)
{
if(p != NULL)
{
free(p);
}
}
void free_and_set_null(void** p)
{
if(*p != NULL)
{
free(*p);
*p = NULL;
}
}

View File

@ -1,683 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work as-is we provide.
* No warranty, express or implied.
* Weve done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
#define malloc safe_malloc
#define strdup safe_strdup
char* replace_prefix(char* original, char* old_prefix, char* new_prefix)
{
char* replaced = NULL;
if(original != NULL && old_prefix != NULL && new_prefix != NULL && strstr(original, old_prefix) == original)
{
int old_prefix_length = strlen(old_prefix);
int new_prefix_length = strlen(new_prefix);
int remainder_length = strlen(original) - old_prefix_length;
int new_length = new_prefix_length + remainder_length;
/* printf("%d %d %d %d\n", old_prefix_length, new_prefix_length, remainder_length, new_length); */
replaced = malloc(new_length+1);
memcpy(replaced, new_prefix, new_prefix_length);
memcpy(replaced+new_prefix_length, original+old_prefix_length, remainder_length);
replaced[new_prefix_length+remainder_length] = '\0';
}
return replaced;
}
char* trim_flanking_whitespace(char* str)
{
int new_start = 0;
int new_length = 0;
char whitespace[5] = { ' ', '\t', '\n', '\r', '\0' };
int num_whitespace_chars = 4;
int index = 0;
int is_whitespace = 1;
int test;
while( (test = str[index]) != '\0' && is_whitespace == 1)
{
int whitespace_index;
is_whitespace = 0;
for(whitespace_index = 0; whitespace_index < num_whitespace_chars && is_whitespace == 0; whitespace_index++)
{
is_whitespace = test == whitespace[whitespace_index] ? 1 : 0;
}
index = is_whitespace == 1 ? index+1 : index;
}
new_start = index;
index = strlen(str) - 1;
is_whitespace = 1;
while( index >= new_start && is_whitespace == 1)
{
int whitespace_index;
is_whitespace = 0;
for(whitespace_index = 0; whitespace_index < num_whitespace_chars && is_whitespace == 0; whitespace_index++)
{
is_whitespace = str[index] == whitespace[whitespace_index] ? 1 : 0;
}
index = is_whitespace == 1 ? index-1 : index;
}
new_length = str[new_start] == '\0' ? 0 : index + 1 - new_start;
if(new_start > 0)
{
for(index = 0; index < new_length; index++)
{
str[index] = str[index+new_start];
}
}
str[new_length] = 0;
return str;
}
int safe_strcmp(const char* str1, const char* str2)
{
if(str1 == NULL && str2 == NULL)
{
return 0;
}
else if(str1 == NULL && str2 != NULL)
{
return 1;
}
else if(str1 != NULL && str2 == NULL)
{
return -1;
}
return strcmp(str1, str2);
}
void to_lowercase(char* str)
{
int i;
for(i = 0; str[i] != '\0'; i++)
{
str[i] = tolower(str[i]);
}
}
void to_uppercase(char* str)
{
int i;
for(i = 0; str[i] != '\0'; i++)
{
str[i] = toupper(str[i]);
}
}
/* returns number freed */
int free_null_terminated_string_array(char** strs)
{
unsigned long str_index = 0;
if(strs != NULL)
{
for(str_index=0; strs[str_index] != NULL; str_index++)
{
free(strs[str_index]);
}
free(strs);
}
return str_index;
}
char** copy_null_terminated_string_array(char** original)
{
unsigned long size;
char** new;
for(size=0; original[size] != NULL ; size++) ;
new = (char**)malloc( (size+1)*sizeof(char*));
for(size=0; original[size] != NULL; size++)
{
new[size] = strdup(original[size]);
}
new[size] = NULL;
return new;
}
char* dynamic_strcat(int num_strs, ...)
{
va_list strs;
int new_length = 0;
int i;
int next_start;
char* new_str;
va_start(strs, num_strs);
for(i=0; i < num_strs; i++)
{
char* next_arg = va_arg(strs, char*);
if(next_arg != NULL)
{
new_length = new_length + strlen(next_arg);
}
}
va_end(strs);
new_str = malloc((1+new_length)*sizeof(char));
va_start(strs, num_strs);
next_start = 0;
for(i=0; i < num_strs; i++)
{
char* next_arg = va_arg(strs, char*);
if(next_arg != NULL)
{
int next_length = strlen(next_arg);
memcpy(new_str+next_start,next_arg, next_length);
next_start = next_start+next_length;
}
}
new_str[next_start] = '\0';
return new_str;
}
char* dcat_and_free(char** one, char** two, int free1, int free2)
{
char* s = NULL;
if(one != NULL && two != NULL) { s = dynamic_strcat(2, *one, *two); }
else if(one != NULL) { s = strdup(*one); }
else if(two != NULL) { s = strdup(*two); }
else { s= strdup(""); }
if(free1){ free(*one); *one=s; }
if(free2){ free(*two); *two=s; }
return s;
}
/*
* line is the line to be parsed -- it is not modified in any way
* max_pieces indicates number of pieces to return, if negative this is determined dynamically
* include_remainder_at_max indicates whether the last piece, when max pieces are reached,
* should be what it would normally be (0) or the entire remainder of the line (1)
* if max_pieces < 0 this parameter is ignored
*
*
* returns all non-separator pieces in a line
* result is dynamically allocated, MUST be freed after call-- even if
* line is empty (you still get a valid char** pointer to to a NULL char*)
*/
char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long *num_pieces)
{
char** split;
*num_pieces = 0;
if(line != NULL)
{
int split_index;
int non_separator_found;
char* dup_line;
char* start;
if(max_pieces < 0)
{
/* count number of separator characters in line -- this count + 1 is an upperbound on number of pieces */
int separator_count = 0;
int line_index;
for(line_index = 0; line[line_index] != '\0'; line_index++)
{
int sep_index;
int found = 0;
for(sep_index =0; found == 0 && sep_index < num_separators; sep_index++)
{
found = separators[sep_index] == line[line_index] ? 1 : 0;
}
separator_count = separator_count+ found;
}
max_pieces = separator_count + 1;
}
split = (char**)malloc((1+max_pieces)*sizeof(char*));
split_index = 0;
split[split_index] = NULL;
dup_line = strdup(line);
start = dup_line;
non_separator_found = 0;
while(non_separator_found == 0)
{
int matches = 0;
int sep_index;
for(sep_index =0; sep_index < num_separators; sep_index++)
{
matches = matches == 1 || separators[sep_index] == start[0] ? 1 : 0;
}
non_separator_found = matches==0 || start[0] == '\0' ? 1 : 0;
if(non_separator_found == 0)
{
start++;
}
}
while(start[0] != '\0' && split_index < max_pieces)
{
/* find first separator index */
int first_separator_index = 0;
int separator_found = 0;
while( separator_found == 0 )
{
int sep_index;
for(sep_index =0; separator_found == 0 && sep_index < num_separators; sep_index++)
{
separator_found = separators[sep_index] == start[first_separator_index] || start[first_separator_index] == '\0' ? 1 : 0;
}
if(separator_found == 0)
{
first_separator_index++;
}
}
/* copy next piece to split array */
if(first_separator_index > 0)
{
char* next_piece = NULL;
if(split_index +1 < max_pieces || include_remainder_at_max <= 0)
{
next_piece = (char*)malloc((first_separator_index+1)*sizeof(char));
memcpy(next_piece, start, first_separator_index);
next_piece[first_separator_index] = '\0';
}
else
{
next_piece = strdup(start);
}
split[split_index] = next_piece;
split[split_index+1] = NULL;
split_index++;
}
/* find next non-separator index, indicating start of next piece */
start = start+ first_separator_index;
non_separator_found = 0;
while(non_separator_found == 0)
{
int matches = 0;
int sep_index;
for(sep_index =0; sep_index < num_separators; sep_index++)
{
matches = matches == 1 || separators[sep_index] == start[0] ? 1 : 0;
}
non_separator_found = matches==0 || start[0] == '\0' ? 1 : 0;
if(non_separator_found == 0)
{
start++;
}
}
}
free(dup_line);
*num_pieces = split_index;
}
else
{
split = (char**)malloc((1)*sizeof(char*));
split[0] = NULL;
}
return split;
}
char* join_strs(char* separator, char** parts, int max_parts, int free_parts, int free_parts_array)
{
char* joined = NULL;
int num_parts = 0;
for(num_parts=0; parts[num_parts] != NULL && (max_parts < 0 || num_parts < max_parts); num_parts++){}
if(num_parts > 0)
{
num_parts--;
joined = strdup(parts[num_parts]);
if(free_parts){ free(parts[num_parts]); }
num_parts--;
while(num_parts >= 0)
{
char* tmp = joined;
joined = dynamic_strcat(3, parts[num_parts], separator, joined);
free(tmp);
if(free_parts){ free(parts[num_parts]); }
num_parts--;
}
}
if(free_parts_array)
{
free(parts);
}
return joined;
}
char* dynamic_replace(char* template_str, char* old, char* new)
{
char *ret;
int i, count = 0;
int newlen = strlen(new);
int oldlen = strlen(old);
char* dyn_template = strdup(template_str);
char* s = dyn_template;
for (i = 0; s[i] != '\0'; i++)
{
if (strstr(&s[i], old) == &s[i])
{
count++;
i += oldlen - 1;
}
}
ret = malloc(i + 1 + count * (newlen - oldlen));
i = 0;
while (*s)
{
if (strstr(s, old) == s)
{
strcpy(&ret[i], new);
i += newlen;
s += oldlen;
}
else
{
ret[i++] = *s++;
}
}
ret[i] = '\0';
free(dyn_template);
return ret;
}
/*
requires expression to be surrounded by '/' characters, and deals with escape
characters '\/', '\r', '\n', and '\t' when escapes haven't been interpreted
(e.g. after recieving regex string from user)
returns 1 on good regex, 0 on bad regex
*/
int convert_to_regex(char* str, regex_t* p)
{
char* trimmed = trim_flanking_whitespace(strdup(str));
int trimmed_length = strlen(trimmed);
char* new = NULL;
int valid = 1;
/* regex must be defined by surrounding '/' characters */
if(trimmed[0] != '/' || trimmed[trimmed_length-1] != '/')
{
valid = 0;
free(trimmed);
}
if(valid == 1)
{
char* internal = (char*)malloc(trimmed_length*sizeof(char));
int internal_length = trimmed_length-2;
int new_index = 0;
int internal_index = 0;
char previous = '\0';
memcpy(internal, trimmed+1, internal_length);
internal[internal_length] = '\0';
free(trimmed);
new = (char*)malloc(trimmed_length*sizeof(char));
while(internal[internal_index] != '\0' && valid == 1)
{
char next = internal[internal_index];
if(next == '/' && previous != '\\')
{
valid = 0;
}
else if((next == 'n' || next == 'r' || next == 't' || next == '/') && previous == '\\')
{
char previous2 = '\0';
if(internal_index >= 2)
{
previous2 = internal[internal_index-2];
}
new_index = previous2 == '\\' ? new_index : new_index-1;
switch(next)
{
case 'n':
new[new_index] = previous2 == '\\' ? next : '\n';
break;
case 'r':
new[new_index] = previous2 == '\\' ? next : '\r';
break;
case 't':
new[new_index] = previous2 == '\\' ? next : '\t';
break;
case '/':
new[new_index] = previous2 == '\\' ? next : '/';
break;
}
previous = '\0';
internal_index++;
new_index++;
}
else
{
new[new_index] = next;
previous = next;
internal_index++;
new_index++;
}
}
if(valid == 0 || previous == '\\')
{
valid = 0;
free(new);
new = NULL;
}
else
{
new[new_index] = '\0';
}
free(internal);
}
if(valid == 1)
{
valid = regcomp(p,new,REG_EXTENDED) == 0 ? 1 : 0;
if(valid == 0)
{
regfree(p);
}
free(new);
}
return valid;
}
/* note: str element in return value is dynamically allocated, need to free */
dyn_read_t dynamic_read(FILE* open_file, char* terminators, int num_terminators, unsigned long* read_length)
{
fpos_t start_pos;
unsigned long size_to_read = 0;
int terminator_found = 0;
int terminator;
char* str;
dyn_read_t ret_value;
fgetpos(open_file, &start_pos);
while(terminator_found == 0)
{
int nextch = fgetc(open_file);
int terminator_index = 0;
for(terminator_index = 0; terminator_index < num_terminators && terminator_found == 0; terminator_index++)
{
terminator_found = nextch == terminators[terminator_index] ? 1 : 0;
terminator = nextch;
}
terminator_found = nextch == EOF ? 1 : terminator_found;
terminator = nextch == EOF ? EOF : nextch;
if(terminator_found == 0)
{
size_to_read++;
}
}
str = (char*)malloc((size_to_read+1)*sizeof(char));
if(size_to_read > 0)
{
int i;
fsetpos(open_file, &start_pos);
for(i=0; i<size_to_read; i++)
{
str[i] = (char)fgetc(open_file);
}
fgetc(open_file); /* read the terminator */
}
str[size_to_read] = '\0';
*read_length = size_to_read;
ret_value.str = str;
ret_value.terminator = terminator;
return ret_value;
}
/* convenience method for calling dynamic_read with end-of-line separators */
int dyn_read_line(FILE* open_file, char** dest, unsigned long* read_len)
{
char line_seps[] = "\r\n";
dyn_read_t read = dynamic_read(open_file, line_seps, 2, read_len);
*dest = read.str;
return read.terminator;
}
unsigned char* read_entire_file(FILE* in, unsigned long read_block_size, unsigned long *length)
{
int max_read_size = read_block_size;
unsigned char* read_string = (unsigned char*)malloc(max_read_size+1);
unsigned long bytes_read = 0;
int end_found = 0;
while(end_found == 0)
{
int nextch = '?';
while(nextch != EOF && bytes_read < max_read_size)
{
nextch = fgetc(in);
if(nextch != EOF)
{
read_string[bytes_read] = (unsigned char)nextch;
bytes_read++;
}
}
read_string[bytes_read] = '\0';
end_found = (nextch == EOF) ? 1 : 0;
if(end_found == 0)
{
unsigned char *new_str;
max_read_size = max_read_size + read_block_size;
new_str = (unsigned char*)malloc(max_read_size+1);
memcpy(new_str, read_string, bytes_read);
free(read_string);
read_string = new_str;
}
}
*length = bytes_read;
return read_string;
}
char** get_shell_command_output_lines(char* command, unsigned long* num_lines)
{
char** ret = NULL;
if(command != NULL && num_lines != NULL)
{
FILE* shell_out = popen(command, "r");
*num_lines = 0;
if(shell_out != NULL)
{
char linebreaks[] = { '\n', '\r' };
unsigned long read_length;
char* all_data = (char*)read_entire_file(shell_out, 2048, &read_length);
ret = split_on_separators(all_data, linebreaks, 2, -1, 0, num_lines);
free(all_data);
pclose(shell_out);
}
}
return ret;
}
/* comparison functions for qsort */
int sort_string_cmp(const void *a, const void *b)
{
const char **a_ptr = (const char **)a;
const char **b_ptr = (const char **)b;
return strcmp(*a_ptr, *b_ptr);
}
int sort_string_icmp(const void *a, const void *b)
{
const char **a_ptr = (const char **)a;
const char **b_ptr = (const char **)b;
return stricmp(*a_ptr, *b_ptr);
}
/* wrappers for qsort calls */
void do_str_sort(char** string_arr, unsigned long string_arr_len)
{
qsort(string_arr, string_arr_len, sizeof(char*), sort_string_cmp);
}
void do_istr_sort(char** string_arr, unsigned long string_arr_len)
{
qsort(string_arr, string_arr_len, sizeof(char*), sort_string_icmp);
}

View File

@ -1,91 +0,0 @@
#include "erics_tools.h"
int main(void)
{
list* l = initialize_list();
list_node* c_node = create_list_node("c");
list_node* a_node = create_list_node("a");
list_node* z_node = create_list_node("z");
list_node* x_node = create_list_node("x");
push_list_node(l, a_node);
remove_internal_list_node(l, a_node);
push_list_node(l, a_node);
push_list(l, "b");
push_list_node(l, c_node);
unshift_list_node(l, z_node);
unshift_list(l, "y");
unshift_list_node(l, x_node);
remove_internal_list_node(l, z_node);
remove_internal_list_node(l, a_node);
remove_internal_list_node(l, x_node);
free_list_node(z_node);
free_list_node(a_node);
free_list_node(x_node);
while(l->length > 0)
{
printf("%s\n", (char*)pop_list(l));
}
unsigned long dl;
destroy_list(l, DESTROY_MODE_IGNORE_VALUES, &dl);
printf("-------queue test-------------\n");
unsigned long priority;
char* id;
priority_queue* pq = initialize_priority_queue();
push_priority_queue(pq, 30, "id_1", "value_1");
push_priority_queue(pq, 10, "id_2", "value_2");
push_priority_queue(pq, 10, "id_3", "value_3");
push_priority_queue(pq, 40, "id_4", "value_4");
push_priority_queue(pq, 5, "id_5", "value_5");
push_priority_queue(pq, 30, "id_6", "value_6");
push_priority_queue(pq, 30, "id_7", "value_7");
printf("queue length = %ld\n", pq->length);
unsigned long num_destroyed;
char* tmp = peek_priority_queue(pq, &priority, &id, 0);
printf("first is \"%s\"\n", tmp);
set_priority_for_id_in_priority_queue(pq, "id_5", 35);
tmp = peek_priority_queue(pq, &priority, &id, 0);
printf("first is \"%s\"\n", tmp);
set_priority_for_id_in_priority_queue(pq, "id_2", 36);
tmp = peek_priority_queue(pq, &priority, &id, 0);
printf("first is \"%s\"\n", tmp);
/*
char** values = (char**)destroy_priority_queue(pq, DESTROY_MODE_RETURN_VALUES, &num_destroyed);
int index = 0;
for(index = 0; values[index] != NULL; index++)
{
printf("%s\n", values[index]);
}
*/
while(pq->length > 0)
{
char* value = (char*)shift_priority_queue(pq, &priority, &id);
printf("%s\n", value);
free(id);
}
destroy_priority_queue(pq, DESTROY_MODE_FREE_VALUES, &dl);
return 0;
}

View File

@ -1,350 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work 'as-is' we provide.
* No warranty, express or implied.
* We've done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
#include <time.h>
void get_max_depth(long_map_node* n, unsigned long* max_depth, unsigned long current_depth);
void get_min_depth(long_map_node* n, unsigned long* min_depth, unsigned long current_depth);
void print_map(long_map_node* n, int depth);
int main (void)
{
unsigned long num_insertions = 2500;
unsigned long max_insertion = 5000;
int num_repeats = 3;
unsigned int seed = (unsigned int)time(NULL);
srand (seed);
printf("TESTING LONG MAP....\n\n");
printf("initializing map....\n");
long_map* lm = initialize_long_map();
printf("initialized!\n\n");
int repeat = 0;
for(repeat =0; repeat < num_repeats; repeat++)
{
printf("randomly inserting %ld integers randomly selected (not in order) between 0 and %ld\n", num_insertions, max_insertion);
unsigned long i;
unsigned long dupes = 0;
for(i=0; i<num_insertions; i++)
{
unsigned long r = (unsigned long)(max_insertion*((double)rand()/(double)RAND_MAX));
void* old;
if( (old = set_long_map_element(lm, r, "a")) != NULL)
{
dupes++;
}
}
unsigned long right_depth = 0;
unsigned long left_depth = 0;
get_max_depth(lm->root->left, &left_depth, 0);
get_max_depth(lm->root->right, &right_depth, 0);
unsigned long original_size = lm->num_elements;
printf("insertion complete\n");
printf("after insertion, tree size = %ld \n", original_size);
printf("(note this may be less than %ld because the same numbers can be selected for insertion more than once, replacing the original node)\n", num_insertions);
printf("dupes = %ld\n", dupes);
printf("depth of left branch = %ld, depth of right branch = %ld\n\n", left_depth, right_depth);
if(repeat+1 < num_repeats)
{
printf("randomly selecting %ld numbers between 0 and %ld to remove from tree.\n", num_insertions, max_insertion);
printf("note that these keys will not necessarily be present in tree -- the selection process is entirely random.\n");
int j;
int found = 0;
for(j=0; j < num_insertions; j++)
{
unsigned long r = (unsigned long)(max_insertion*((double)rand()/(double)RAND_MAX));
if( remove_long_map_element(lm, r) != NULL)
{
found++;
}
}
right_depth = 0;
left_depth = 0;
get_max_depth(lm->root->left, &left_depth, 0);
get_max_depth(lm->root->right, &right_depth, 0);
printf("removal complete\n");
printf("after removal, tree size = %ld \n", lm->num_elements);
printf("depth of left branch = %ld, depth of right branch = %ld\n", left_depth, right_depth);
if(original_size - found == lm->num_elements)
{
printf("size consistent with number of nodes successfully removed\n\n");
}
else
{
printf("SIZE IS BAD -- IS NOT CONSISTENT WITH NUMBER OF NODES REMOVED !!!!\n\n");
}
printf("removing remaining nodes in tree in random order\n");
unsigned long length;
unsigned long *keys = get_sorted_long_map_keys(lm, &length);
while(lm->root != NULL && lm->num_elements > 0)
{
unsigned long r = (unsigned long)(length*((double)rand()/(double)RAND_MAX));
if( remove_long_map_element(lm, keys[r]) != NULL)
{
found++;
if(original_size - found != lm->num_elements)
{
printf("SIZE IS BAD!!!!\n");
}
}
}
printf("done removing remaining nodes\n");
printf("tree size is now %ld, and root is %s\n\n", lm->num_elements, lm->root == NULL ? "null" : "not null");
free(keys);
printf("repeating insertion/deletion\n\n");
}
else
{
unsigned long num_destroyed;
printf("destroying map...\n");
void** values = destroy_long_map(lm, DESTROY_MODE_RETURN_VALUES, &num_destroyed);
printf("map destroyed.\n");
int v=0;
for(v=0; values[v] != NULL; v++){}
free(values);
printf("number of values returned after map destruction = %d\n", v);
}
}
printf("LONG MAP TESTING COMPLETE. TESTING STRING MAP (WITH KEY STORAGE) \n\n");
printf("initializing map....\n");
string_map* sm = initialize_string_map(1);
printf("initialized!\n\n");
repeat = 0;
for(repeat =0; repeat < num_repeats; repeat++)
{
printf("randomly inserting %ld integer strings randomly selected (not in order) between 0 and %ld\n", num_insertions, max_insertion);
unsigned long i;
unsigned long dupes = 0;
for(i=0; i<num_insertions; i++)
{
unsigned long r = (unsigned long)(max_insertion*((double)rand()/(double)RAND_MAX));
char* new_str = (char*)malloc(40*sizeof(char));
sprintf(new_str, "%ld", r);
void* old;
if( (old = set_string_map_element(sm, new_str, "a")) != NULL )
{
dupes++;
}
free(new_str);
}
unsigned long right_depth = 0;
unsigned long left_depth = 0;
get_max_depth(sm->lm.root->left, &left_depth, 0);
get_max_depth(sm->lm.root->right, &right_depth, 0);
unsigned long original_size = sm->num_elements;
printf("insertion complete\n");
printf("after insertion, tree size = %ld \n", original_size);
printf("(note this may be less than %ld because the same numbers can be selected for insertion more than once, replacing the original node)\n", num_insertions);
printf("dupes = %ld\n", dupes);
printf("depth of left branch = %ld, depth of right branch = %ld\n\n", left_depth, right_depth);
if(repeat+1 < num_repeats)
{
printf("randomly selecting %ld numbers between 0 and %ld to remove from tree.\n", num_insertions, max_insertion);
printf("note that these keys will not necessarily be present in tree -- the selection process is entirely random.\n");
int j;
int found = 0;
for(j=0; j < num_insertions; j++)
{
unsigned long r = (unsigned long)(max_insertion*((double)rand()/(double)RAND_MAX));
char* new_str = (char*)malloc(40*sizeof(char));
sprintf(new_str, "%ld", r);
void* old;
if( (old = remove_string_map_element(sm, new_str)) != NULL)
{
found++;
}
free(new_str);
}
right_depth = 0;
left_depth = 0;
get_max_depth(sm->lm.root->left, &left_depth, 0);
get_max_depth(sm->lm.root->right, &right_depth, 0);
printf("removal complete\n");
printf("after removal, tree size = %ld \n", sm->num_elements);
printf("depth of left branch = %ld, depth of right branch = %ld\n", left_depth, right_depth);
if(original_size - found == sm->num_elements)
{
printf("size consistent with number of nodes successfully removed\n\n");
}
else
{
printf("SIZE IS BAD -- IS NOT CONSISTENT WITH NUMBER OF NODES REMOVED !!!!\n\n");
}
printf("removing remaining nodes in tree in random order\n");
unsigned long length = sm->num_elements;
char** keys = get_string_map_keys(sm, &length);
while(sm->lm.root != NULL && sm->num_elements > 0)
{
unsigned long r = (unsigned long)(length*((double)rand()/(double)RAND_MAX));
if( remove_string_map_element(sm, keys[r]) != NULL)
{
found++;
if(original_size - found != sm->num_elements)
{
printf("SIZE IS BAD!!!!\n");
}
}
}
int k;
for(k=0; k<length; k++)
{
free(keys[k]);
}
free(keys);
printf("done removing remaining nodes\n");
printf("tree size is now %ld, and root is %s\n\n", sm->num_elements, sm->lm.root == NULL ? "null" : "not null");
printf("repeating insertion/deletion\n\n");
}
else
{
unsigned long num_destroyed;
printf("destroying map...\n");
void** values = destroy_string_map(sm, DESTROY_MODE_RETURN_VALUES, &num_destroyed);
printf("map destroyed.\n");
int v=0;
for(v=0; values[v] != NULL; v++){ }
free(values);
printf("number of values returned after map destruction = %d\n", v);
}
}
return(0);
}
void get_max_depth(long_map_node* n, unsigned long* max_depth, unsigned long current_depth)
{
if(n == NULL)
{
*max_depth = current_depth > *max_depth ? current_depth : *max_depth;
return;
}
else
{
*max_depth = current_depth+1 > *max_depth ? current_depth+1 : *max_depth;
get_max_depth(n->left, max_depth, current_depth+1);
get_max_depth(n->right, max_depth, current_depth+1);
}
}
void get_min_depth(long_map_node* n, unsigned long* min_depth, unsigned long current_depth)
{
if(n == NULL)
{
return;
}
else if(n->left == NULL && n->right == NULL)
{
*min_depth = current_depth < *min_depth ? current_depth : *min_depth;
}
else
{
get_min_depth(n->left, min_depth, current_depth+1);
get_min_depth(n->right, min_depth, current_depth+1);
}
}
void print_map(long_map_node* n, int depth)
{
if(n == NULL)
{
return;
}
int i;
for(i=0; i < depth; i++){ printf("\t");}
printf("%ld (%d)\n", n->key, n->balance);
for(i=0; i < depth; i++){ printf("\t");}
printf("left:\n");
print_map(n->left, depth+1);
for(i=0; i < depth; i++){ printf("\t");}
printf("right:\n");
print_map(n->right, depth+1);
}

View File

@ -1,26 +0,0 @@
#include "erics_tools.h"
int main(void)
{
FILE* f = fopen("tmp", "r");
char terminators[] = "\n\r";
unsigned long length;
char* file_data = (char*)read_entire_file(f, 100, &length);
printf("%s\n", file_data);
fclose(f);
f = fopen("tmp", "r");
dyn_read_t next;
next.terminator = '\n';
while(next.terminator != EOF)
{
next = dynamic_read(f, terminators, 2, &length);
printf("read \"%s\"\n", next.str);
free(next.str);
}
fclose(f);
return 0;
}

View File

@ -1,911 +0,0 @@
/*
* Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
*
* This work 'as-is' we provide.
* No warranty, express or implied.
* We've done our best,
* to debug and test.
* Liability for damages denied.
*
* Permission is granted hereby,
* to copy, share, and modify.
* Use as is fit,
* free or for profit.
* On this notice these rights rely.
*
*
*
* Note that unlike other portions of Gargoyle this code
* does not fall under the GPL, but the rather whimsical
* 'Poetic License' above.
*
* Basically, this library contains a bunch of utilities
* that I find useful. I'm sure other libraries exist
* that are just as good or better, but I like these tools
* because I personally wrote them, so I know their quirks.
* (i.e. I know where the bodies are buried). I want to
* make sure that I can re-use these utilities for whatever
* code I may want to write in the future be it
* proprietary or open-source, so I've put them under
* a very, very permissive license.
*
* If you find this code useful, use it. If not, don't.
* I really don't care.
*
*/
#include "erics_tools.h"
#define malloc safe_malloc
#define strdup safe_strdup
/* internal utility structures/ functions */
typedef struct stack_node_struct
{
long_map_node** node_ptr;
signed char direction;
struct stack_node_struct* previous;
} stack_node;
static void** destroy_long_map_values(long_map* map, int destruction_type, unsigned long* num_destroyed);
static void apply_to_every_long_map_node(long_map_node* node, void (*apply_func)(unsigned long key, void* value));
static void apply_to_every_string_map_node(long_map_node* node, unsigned char has_key, void (*apply_func)(char* key, void* value));
static void get_sorted_node_keys(long_map_node* node, unsigned long* key_list, unsigned long* next_key_index, int depth);
static void get_sorted_node_values(long_map_node* node, void** value_list, unsigned long* next_value_index, int depth);
static signed char rebalance (long_map_node** n, signed char direction, signed char update_op);
static void rotate_right (long_map_node** parent);
static void rotate_left (long_map_node** parent);
/* internal for string map */
typedef struct
{
char* key;
void* value;
} string_map_key_value;
static unsigned long sdbm_string_hash(const char *key);
/***************************************************
* For testing only
***************************************************/
/*
void print_list(stack_node *l);
void print_list(stack_node *l)
{
if(l != NULL)
{
printf(" list key = %ld, dir=%d, \n", (*(l->node_ptr))->key, l->direction);
print_list(l->previous);
}
}
*/
/******************************************************
* End testing Code
*******************************************************/
/***************************************************
* string_map function definitions
***************************************************/
string_map* initialize_string_map(unsigned char store_keys)
{
string_map* map = (string_map*)malloc(sizeof(string_map));
map->store_keys = store_keys;
map->lm.root = NULL;
map->lm.num_elements = 0;
map->num_elements = map->lm.num_elements;
return map;
}
void* get_string_map_element(string_map* map, const char* key)
{
unsigned long hashed_key = sdbm_string_hash(key);
void* return_value = get_long_map_element( &(map->lm), hashed_key);
if(return_value != NULL && map->store_keys)
{
string_map_key_value* r = (string_map_key_value*)return_value;
return_value = r->value;
}
map->num_elements = map->lm.num_elements;
return return_value;
}
void* set_string_map_element(string_map* map, const char* key, void* value)
{
unsigned long hashed_key = sdbm_string_hash(key);
void* return_value = NULL;
if(map->store_keys)
{
string_map_key_value* kv = (string_map_key_value*)malloc(sizeof(string_map_key_value));
kv->key = strdup(key);
kv->value = value;
return_value = set_long_map_element( &(map->lm), hashed_key, kv);
if(return_value != NULL)
{
string_map_key_value* r = (string_map_key_value*)return_value;
return_value = r->value;
free(r->key);
free(r);
}
}
else
{
return_value = set_long_map_element( &(map->lm), hashed_key, value);
}
map->num_elements = map->lm.num_elements;
return return_value;
}
void* remove_string_map_element(string_map* map, const char* key)
{
unsigned long hashed_key = sdbm_string_hash(key);
void* return_value = remove_long_map_element( &(map->lm), hashed_key);
if(return_value != NULL && map->store_keys)
{
string_map_key_value* r = (string_map_key_value*)return_value;
return_value = r->value;
free(r->key);
free(r);
}
map->num_elements = map->lm.num_elements;
return return_value;
}
char** get_string_map_keys(string_map* map, unsigned long* num_keys_returned)
{
char** str_keys;
str_keys = (char**)malloc((map->num_elements+1)*sizeof(char*));
str_keys[0] = NULL;
*num_keys_returned = 0;
if(map->store_keys && map->num_elements > 0)
{
unsigned long list_length;
void** long_values = get_sorted_long_map_values( &(map->lm), &list_length);
unsigned long key_index;
for(key_index = 0; key_index < list_length; key_index++)
{
str_keys[key_index] = strdup( ((string_map_key_value*)(long_values[key_index]))->key);
*num_keys_returned = *num_keys_returned + 1;
}
str_keys[list_length] = NULL;
free(long_values);
}
return str_keys;
}
void** get_string_map_values(string_map* map, unsigned long* num_values_returned)
{
void** values = NULL;
if(map != NULL)
{
values = get_sorted_long_map_values ( &(map->lm), num_values_returned );
}
return values;
}
void** destroy_string_map(string_map* map, int destruction_type, unsigned long* num_destroyed)
{
void** return_values = NULL;
if(map != NULL)
{
if(map->store_keys)
{
void** kvs = destroy_long_map_values( &(map->lm), DESTROY_MODE_RETURN_VALUES, num_destroyed );
unsigned long kv_index = 0;
for(kv_index=0; kv_index < *num_destroyed; kv_index++)
{
string_map_key_value* kv = (string_map_key_value*)kvs[kv_index];
void* value = kv->value;
free(kv->key);
free(kv);
if(destruction_type == DESTROY_MODE_FREE_VALUES)
{
free(value);
}
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
kvs[kv_index] = value;
}
}
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
return_values = kvs;
}
else
{
free(kvs);
}
}
else
{
return_values = destroy_long_map_values( &(map->lm), destruction_type, num_destroyed );
}
free(map);
}
return return_values;
}
/***************************************************
* long_map function definitions
***************************************************/
long_map* initialize_long_map(void)
{
long_map* map = (long_map*)malloc(sizeof(long_map));
map->root = NULL;
map->num_elements = 0;
return map;
}
void* get_long_map_element(long_map* map, unsigned long key)
{
void* value = NULL;
if(map->root != NULL)
{
long_map_node* parent_node = map->root;
long_map_node* next_node;
while( key != parent_node->key && (next_node = (long_map_node *)(key < parent_node->key ? parent_node->left : parent_node->right)) != NULL)
{
parent_node = next_node;
}
if(parent_node->key == key)
{
value = parent_node->value;
}
}
return value;
}
void* get_smallest_long_map_element(long_map* map, unsigned long* smallest_key)
{
void* value = NULL;
if(map->root != NULL)
{
long_map_node* next_node = map->root;
while( next_node->left != NULL)
{
next_node = next_node->left;
}
value = next_node->value;
*smallest_key = next_node->key;
}
return value;
}
void* get_largest_long_map_element(long_map* map, unsigned long* largest_key)
{
void* value = NULL;
if(map->root != NULL)
{
long_map_node* next_node = map->root;
while( next_node->right != NULL)
{
next_node = next_node->right;
}
value = next_node->value;
*largest_key = next_node->key;
}
return value;
}
void* remove_smallest_long_map_element(long_map* map, unsigned long* smallest_key)
{
get_smallest_long_map_element(map, smallest_key);
return remove_long_map_element(map, *smallest_key);
}
void* remove_largest_long_map_element(long_map* map, unsigned long* largest_key)
{
get_largest_long_map_element(map, largest_key);
return remove_long_map_element(map, *largest_key);
}
/* if replacement performed, returns replaced value, otherwise null */
void* set_long_map_element(long_map* map, unsigned long key, void* value)
{
stack_node* parent_list = NULL;
void* old_value = NULL;
int old_value_found = 0;
long_map_node* parent_node;
long_map_node* next_node;
stack_node* next_parent;
stack_node* previous_parent;
signed char new_balance;
long_map_node* new_node = (long_map_node*)malloc(sizeof(long_map_node));
new_node->value = value;
new_node->key = key;
new_node->left = NULL;
new_node->right = NULL;
new_node->balance = 0;
if(map->root == NULL)
{
map->root = new_node;
}
else
{
parent_node = map->root;
next_parent = (stack_node*)malloc(sizeof(stack_node));
next_parent->node_ptr = &(map->root);
next_parent->previous = parent_list;
parent_list = next_parent;
while( key != parent_node->key && (next_node = (key < parent_node->key ? parent_node->left : parent_node->right) ) != NULL)
{
next_parent = (stack_node*)malloc(sizeof(stack_node));
next_parent->node_ptr = key < parent_node->key ? &(parent_node->left) : &(parent_node->right);
next_parent->previous = parent_list;
next_parent->previous->direction = key < parent_node->key ? -1 : 1;
parent_list = next_parent;
parent_node = next_node;
}
if(key == parent_node->key)
{
old_value = parent_node->value;
old_value_found = 1;
parent_node->value = value;
free(new_node);
/* we merely replaced a node, no need to rebalance */
}
else
{
if(key < parent_node->key)
{
parent_node->left = (void*)new_node;
parent_list->direction = -1;
}
else
{
parent_node->right = (void*)new_node;
parent_list->direction = 1;
}
/* we inserted a node, rebalance */
previous_parent = parent_list;
new_balance = 1; /* initial value is not used, but must not be 0 for initial loop condition */
while(previous_parent != NULL && new_balance != 0)
{
new_balance = rebalance(previous_parent->node_ptr, previous_parent->direction, 1);
previous_parent = previous_parent->previous;
}
}
}
while(parent_list != NULL)
{
previous_parent = parent_list;
parent_list = previous_parent->previous;
free(previous_parent);
}
if(old_value_found == 0)
{
map->num_elements = map->num_elements + 1;
}
return old_value;
}
void* remove_long_map_element(long_map* map, unsigned long key)
{
void* value = NULL;
long_map_node* root_node = map->root;
stack_node* parent_list = NULL;
long_map_node* remove_parent;
long_map_node* remove_node;
long_map_node* next_node;
long_map_node* replacement;
long_map_node* replacement_parent;
long_map_node* replacement_next;
stack_node* next_parent;
stack_node* previous_parent;
stack_node* replacement_stack_node;
signed char new_balance;
if(root_node != NULL)
{
remove_parent = root_node;
remove_node = key < remove_parent->key ? remove_parent->left : remove_parent->right;
if(remove_node != NULL && key != remove_parent->key)
{
next_parent = (stack_node*)malloc(sizeof(stack_node));
next_parent->node_ptr = &(map->root);
next_parent->previous = parent_list;
parent_list = next_parent;
while( key != remove_node->key && (next_node = (key < remove_node->key ? remove_node->left : remove_node->right)) != NULL)
{
next_parent = (stack_node*)malloc(sizeof(stack_node));
next_parent->node_ptr = key < remove_parent->key ? &(remove_parent->left) : &(remove_parent->right);
next_parent->previous = parent_list;
next_parent->previous->direction = key < remove_parent->key ? -1 : 1;
parent_list = next_parent;
remove_parent = remove_node;
remove_node = next_node;
}
parent_list->direction = key < remove_parent-> key ? -1 : 1;
}
else
{
remove_node = remove_parent;
}
if(key == remove_node->key)
{
/* find replacement for node we are deleting */
if( remove_node->right == NULL )
{
replacement = remove_node->left;
}
else if( remove_node->right->left == NULL)
{
replacement = remove_node->right;
replacement->left = remove_node->left;
replacement->balance = remove_node->balance;
/* put pointer to replacement node into list for balance update */
replacement_stack_node = (stack_node*)malloc(sizeof(stack_node));;
replacement_stack_node->previous = parent_list;
replacement_stack_node->direction = 1; /* replacement is from right */
if(remove_node == remove_parent) /* special case for root node */
{
replacement_stack_node->node_ptr = &(map->root);
}
else
{
replacement_stack_node->node_ptr = key < remove_parent-> key ? &(remove_parent->left) : &(remove_parent->right);
}
parent_list = replacement_stack_node;
}
else
{
/* put pointer to replacement node into list for balance update */
replacement_stack_node = (stack_node*)malloc(sizeof(stack_node));
replacement_stack_node->previous = parent_list;
replacement_stack_node->direction = 1; /* we always look for replacement on right */
if(remove_node == remove_parent) /* special case for root node */
{
replacement_stack_node->node_ptr = &(map->root);
}
else
{
replacement_stack_node->node_ptr = key < remove_parent-> key ? &(remove_parent->left) : &(remove_parent->right);
}
parent_list = replacement_stack_node;
/*
* put pointer to replacement node->right into list for balance update
* this node will have to be updated with the proper pointer
* after we have identified the replacement
*/
replacement_stack_node = (stack_node*)malloc(sizeof(stack_node));
replacement_stack_node->previous = parent_list;
replacement_stack_node->direction = -1; /* we always look for replacement to left of this node */
parent_list = replacement_stack_node;
/* find smallest node on right (large) side of tree */
replacement_parent = remove_node->right;
replacement = replacement_parent->left;
while((replacement_next = replacement->left) != NULL)
{
next_parent = (stack_node*)malloc(sizeof(stack_node));
next_parent->node_ptr = &(replacement_parent->left);
next_parent->previous = parent_list;
next_parent->direction = -1; /* we always go left */
parent_list = next_parent;
replacement_parent = replacement;
replacement = replacement_next;
}
replacement_parent->left = replacement->right;
replacement->left = remove_node->left;
replacement->right = remove_node->right;
replacement->balance = remove_node->balance;
replacement_stack_node->node_ptr = &(replacement->right);
}
/* insert replacement at proper location in tree */
if(remove_node == remove_parent)
{
map->root = replacement;
}
else
{
remove_parent->left = remove_node == remove_parent->left ? replacement : remove_parent->left;
remove_parent->right = remove_node == remove_parent->right ? replacement : remove_parent->right;
}
/* rebalance tree */
previous_parent = parent_list;
new_balance = 0;
while(previous_parent != NULL && new_balance == 0)
{
new_balance = rebalance(previous_parent->node_ptr, previous_parent->direction, -1);
previous_parent = previous_parent->previous;
}
/*
* since we found a value to remove, decrease number of elements in map
* set return value to the deleted node's value and free the node
*/
map->num_elements = map->num_elements - 1;
value = remove_node->value;
free(remove_node);
}
}
while(parent_list != NULL)
{
previous_parent = parent_list;
parent_list = previous_parent->previous;
free(previous_parent);
}
return value;
}
/* note: returned keys are dynamically allocated, you need to free them! */
unsigned long* get_sorted_long_map_keys(long_map* map, unsigned long* num_keys_returned)
{
unsigned long* key_list = (unsigned long*)malloc((map->num_elements)*sizeof(unsigned long));
unsigned long next_key_index = 0;
get_sorted_node_keys(map->root, key_list, &next_key_index, 0);
*num_keys_returned = map->num_elements;
return key_list;
}
void** get_sorted_long_map_values(long_map* map, unsigned long* num_values_returned)
{
void** value_list = (void**)malloc((map->num_elements+1)*sizeof(void*));
unsigned long next_value_index = 0;
get_sorted_node_values(map->root, value_list, &next_value_index, 0);
value_list[map->num_elements] = NULL; /* since we're dealing with pointers make list null terminated */
*num_values_returned = map->num_elements;
return value_list;
}
void** destroy_long_map(long_map* map, int destruction_type, unsigned long* num_destroyed)
{
void** return_values = NULL;
unsigned long return_index = 0;
*num_destroyed = 0;
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
return_values = (void**)malloc((map->num_elements+1)*sizeof(void*));
return_values[map->num_elements] = NULL;
}
while(map->num_elements > 0)
{
unsigned long smallest_key = 0;
void* removed_value = remove_smallest_long_map_element(map, &smallest_key);
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
return_values[return_index] = removed_value;
}
if(destruction_type == DESTROY_MODE_FREE_VALUES)
{
free(removed_value);
}
return_index++;
*num_destroyed = *num_destroyed + 1;
}
free(map);
return return_values;
}
void apply_to_every_long_map_value(long_map* map, void (*apply_func)(unsigned long key, void* value))
{
apply_to_every_long_map_node(map->root, apply_func);
}
void apply_to_every_string_map_value(string_map* map, void (*apply_func)(char* key, void* value))
{
apply_to_every_string_map_node( (map->lm).root, map->store_keys, apply_func);
}
/***************************************************
* internal utility function definitions
***************************************************/
static void** destroy_long_map_values(long_map* map, int destruction_type, unsigned long* num_destroyed)
{
void** return_values = NULL;
unsigned long return_index = 0;
*num_destroyed = 0;
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
return_values = (void**)malloc((map->num_elements+1)*sizeof(void*));
return_values[map->num_elements] = NULL;
}
while(map->num_elements > 0)
{
unsigned long smallest_key = 0;
void* removed_value = remove_smallest_long_map_element(map, &smallest_key);
if(destruction_type == DESTROY_MODE_RETURN_VALUES)
{
return_values[return_index] = removed_value;
}
if(destruction_type == DESTROY_MODE_FREE_VALUES)
{
free(removed_value);
}
return_index++;
*num_destroyed = *num_destroyed + 1;
}
return return_values;
}
static void apply_to_every_long_map_node(long_map_node* node, void (*apply_func)(unsigned long key, void* value))
{
if(node != NULL)
{
apply_to_every_long_map_node(node->left, apply_func);
apply_func(node->key, node->value);
apply_to_every_long_map_node(node->right, apply_func);
}
}
static void apply_to_every_string_map_node(long_map_node* node, unsigned char has_key, void (*apply_func)(char* key, void* value))
{
if(node != NULL)
{
apply_to_every_string_map_node(node->left, has_key, apply_func);
if(has_key)
{
string_map_key_value* kv = (string_map_key_value*)(node->value);
apply_func(kv->key, kv->value);
}
else
{
apply_func(NULL, node->value);
}
apply_to_every_string_map_node(node->right, has_key, apply_func);
}
}
static void get_sorted_node_keys(long_map_node* node, unsigned long* key_list, unsigned long* next_key_index, int depth)
{
if(node != NULL)
{
get_sorted_node_keys(node->left, key_list, next_key_index, depth+1);
key_list[ *next_key_index ] = node->key;
(*next_key_index)++;
get_sorted_node_keys(node->right, key_list, next_key_index, depth+1);
}
}
static void get_sorted_node_values(long_map_node* node, void** value_list, unsigned long* next_value_index, int depth)
{
if(node != NULL)
{
get_sorted_node_values(node->left, value_list, next_value_index, depth+1);
value_list[ *next_value_index ] = node->value;
(*next_value_index)++;
get_sorted_node_values(node->right, value_list, next_value_index, depth+1);
}
}
/*
* direction = -1 indicates left subtree updated, direction = 1 for right subtree
* update_op = -1 indicates delete node, update_op = 1 for insert node
*/
static signed char rebalance (long_map_node** n, signed char direction, signed char update_op)
{
/*
printf( "original: key = %ld, balance = %d, update_op=%d, direction=%d\n", (*n)->key, (*n)->balance, update_op, direction);
*/
(*n)->balance = (*n)->balance + (update_op*direction);
if( (*n)->balance < -1)
{
if((*n)->left->balance < 0)
{
rotate_right(n);
(*n)->right->balance = 0;
(*n)->balance = 0;
}
else if((*n)->left->balance == 0)
{
rotate_right(n);
(*n)->right->balance = -1;
(*n)->balance = 1;
}
else if((*n)->left->balance > 0)
{
rotate_left( &((*n)->left) );
rotate_right(n);
/*
if( (*n)->balance < 0 )
{
(*n)->left->balance = 0;
(*n)->right->balance = 1;
}
else if( (*n)->balance == 0 )
{
(*n)->left->balance = 0;
(*n)->right->balance = 0;
}
else if( (*n)->balance > 0 )
{
(*n)->left->balance = -1;
(*n)->right->balance = 0;
}
*/
(*n)->left->balance = (*n)->balance > 0 ? -1 : 0;
(*n)->right->balance = (*n)->balance < 0 ? 1 : 0;
(*n)->balance = 0;
}
}
if( (*n)->balance > 1)
{
if((*n)->right->balance > 0)
{
rotate_left(n);
(*n)->left->balance = 0;
(*n)->balance = 0;
}
else if ((*n)->right->balance == 0)
{
rotate_left(n);
(*n)->left->balance = 1;
(*n)->balance = -1;
}
else if((*n)->right->balance < 0)
{
rotate_right( &((*n)->right) );
rotate_left(n);
/*
if( (*n)->balance < 0 )
{
(*n)->left->balance = 0;
(*n)->right->balance = 1;
}
else if( (*n)->balance == 0 )
{
(*n)->left->balance = 0;
(*n)->right->balance = 0;
}
else if( (*n)->balance > 0 )
{
(*n)->left->balance = -1;
(*n)->right->balance = 0;
}
*/
(*n)->left->balance = (*n)->balance > 0 ? -1 : 0;
(*n)->right->balance = (*n)->balance < 0 ? 1 : 0;
(*n)->balance = 0;
}
}
/*
printf( "key = %ld, balance = %d\n", (*n)->key, (*n)->balance);
*/
return (*n)->balance;
}
static void rotate_right (long_map_node** parent)
{
long_map_node* old_parent = *parent;
long_map_node* pivot = old_parent->left;
old_parent->left = pivot->right;
pivot->right = old_parent;
*parent = pivot;
}
static void rotate_left (long_map_node** parent)
{
long_map_node* old_parent = *parent;
long_map_node* pivot = old_parent->right;
old_parent->right = pivot->left;
pivot->left = old_parent;
*parent = pivot;
}
/***************************************************************************
* This algorithm was created for the sdbm database library (a public-domain
* reimplementation of ndbm) and seems to work relatively well in
* scrambling bits
*
*
* This code was derived from code found at:
* http://www.cse.yorku.ca/~oz/hash.html
***************************************************************************/
static unsigned long sdbm_string_hash(const char *key)
{
unsigned long hashed_key = 0;
int index = 0;
unsigned int nextch;
while(key[index] != '\0')
{
nextch = key[index];
hashed_key = nextch + (hashed_key << 6) + (hashed_key << 16) - hashed_key;
index++;
}
return hashed_key;
}

View File

@ -1,83 +0,0 @@
#
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2009 Eric Bishop <eric@gargoyle-router.com>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=libiptbwctl
PKG_VERSION:=$(GARGOYLE_VERSION)
ifeq ($(GARGOYLE_VERSION),)
PKG_VERSION:=1.0.0
endif
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/libiptbwctl
include $(INCLUDE_DIR)/package.mk
define Package/libiptbwctl
SECTION:=net
CATEGORY:=Network
DEPENDS:=+iptables-mod-bandwidth
TITLE:=IPT bandwidth control library
URL:=http://www.gargoyle-router.com
MAINTAINER:=Eric Bishop <eric@gargoyle-router.com>
endef
define Package/libiptbwctl/description
IPT bandwidth control library
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Configure
endef
define Build/Compile
-$(MAKE) -C $(PKG_BUILD_DIR) clean
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
STAGING_DIR="$(STAGING_DIR)" \
CFLAGS="$(TARGET_CFLAGS) -I $(STAGING_DIR)/usr/include" \
LDFLAGS="$(TARGET_LDFLAGS) -L $(STAGING_DIR)/usr/lib" \
all
mkdir -p $(STAGING_DIR)/usr/include/
$(CP) $(PKG_BUILD_DIR)/*.h $(STAGING_DIR)/usr/include/
mkdir -p $(STAGING_DIR)/usr/lib
$(CP) $(PKG_BUILD_DIR)/*.so* $(STAGING_DIR)/usr/lib/
$(MAKE) -C $(PKG_BUILD_DIR)/utils \
$(TARGET_CONFIGURE_OPTS) \
STAGING_DIR="$(STAGING_DIR)" \
CFLAGS="$(TARGET_CFLAGS) -I $(STAGING_DIR)/usr/include" \
LDFLAGS="$(TARGET_LDFLAGS) -L $(STAGING_DIR)/usr/lib" \
all
endef
define Package/libiptbwctl/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/usr/bin
$(CP) $(PKG_BUILD_DIR)/*.so* $(1)/usr/lib/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/utils/bw_get $(1)/usr/bin/bw_get
$(INSTALL_BIN) $(PKG_BUILD_DIR)/utils/bw_set $(1)/usr/bin/bw_set
$(INSTALL_BIN) $(PKG_BUILD_DIR)/utils/bw_print_history_file $(1)/usr/bin/bw_print_history_file
$(INSTALL_BIN) $(PKG_BUILD_DIR)/utils/set_kernel_timezone $(1)/usr/bin/set_kernel_timezone
endef
$(eval $(call BuildPackage,libiptbwctl))

View File

@ -1,70 +0,0 @@
VERSION=1
ifeq ($(CC),)
CC=gcc
endif
ifeq ($(LD),)
LD=ld
endif
ifeq ($(AR),)
AR=ar
endif
ifeq ($(RANLIB),)
RANLIB=ranlib
endif
OS=$(shell uname)
ifeq ($(OS),Darwin)
LINK=$(LD)
SHLIB_EXT=dylib
SHLIB_FLAGS=-dylib
SHLIB_FILE=libiptbwctl.$(SHLIB_EXT).$(VERSION)
else
LINK=$(CC)
SHLIB_EXT=so
SHLIB_FILE=libiptbwctl.$(SHLIB_EXT).$(VERSION)
SHLIB_FLAGS=-shared -Wl,-soname,$(SHLIB_FILE)
endif
CFLAGS:=$(CFLAGS) -Os
WARNING_FLAGS=-Wall -Wstrict-prototypes
all: libiptbwctl
libiptbwctl: libiptbwctl.$(SHLIB_EXT) libiptbwctl.a
libiptbwctl.a: ipt_bwctl_static.o ipt_bwctl_safe_malloc_static.o
if [ -e $@ ] ; then rm $@ ; fi
$(AR) rc $@ $^
$(RANLIB) $@
libiptbwctl.$(SHLIB_EXT) : ipt_bwctl_dyn.o ipt_bwctl_safe_malloc_dyn.o
if [ -e libiptbwctl.$(SHLIB_EXT) ] ; then rm libiptbwctl.$(SHLIB_EXT)* ; fi
$(LINK) $(LDFLAGS) $(SHLIB_FLAGS) -o $(SHLIB_FILE) $^ -lc
ln -s $(SHLIB_FILE) libiptbwctl.$(SHLIB_EXT)
%_dyn.o: %.c
$(CC) $(CFLAGS) -fPIC $(WARNING_FLAGS) -o $@ -c $^
%_static.o: %.c
$(CC) $(CFLAGS) $(WARNING_FLAGS) -o $@ -c $^
clean:
cd utils
rm -rf bw_get bw_set *.a *.o *~ .*sw*
cd ..
if [ -n "$(SHLIB_EXT)" ] ; then rm -rf *.$(SHLIB_EXT)* ; fi
rm -rf *.a *.o *~ .*sw*

File diff suppressed because it is too large Load Diff

View File

@ -1,161 +0,0 @@
/* libiptbwctl -- A userspace library for querying the bandwidth iptables module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/ipc.h>
#include <errno.h>
#include <sys/sem.h>
#include <sys/time.h>
#include <sys/syscall.h>
#define BANDWIDTH_QUERY_LENGTH 16384
/* socket id parameters (for userspace i/o) */
#define BANDWIDTH_SET 2048
#define BANDWIDTH_GET 2049
/* max id length */
#define BANDWIDTH_MAX_ID_LENGTH 50
/* pick something rather random... let's make it end in 666 to
* freak out the crazy fundies out there ;-) */
#define BANDWIDTH_SEMAPHORE_KEY 12699666
/* possible reset intervals */
#define BANDWIDTH_MINUTE 80
#define BANDWIDTH_HOUR 81
#define BANDWIDTH_DAY 82
#define BANDWIDTH_WEEK 83
#define BANDWIDTH_MONTH 84
#define BANDWIDTH_NEVER 85
#pragma pack(push, 1)
typedef struct ip_bw_struct
{
uint32_t ip;
uint64_t bw;
}ip_bw;
/*
* format of response:
* byte 1 : error code (0 for ok)
* bytes 2-5 : total_num_ips found in query (further gets may be necessary to retrieve them)
* bytes 6-9 : start_index, index (in a list of total_num_ips) of first ip in response
* bytes 10-13 : num_ips_in_response, number of ips in this response
* bytes 14-21 : reset_interval (helps deal with DST shifts in userspace)
* bytes 22-29 : reset_time (helps deal with DST shifts in userspace)
* byte 30 : reset_is_constant_interval (helps deal with DST shifts in userspace)
* remaining bytes contain blocks of ip data
* format is dependent on whether history was queried
*/
typedef struct ip_bw_kernel_data_item_struct
{
uint32_t ip;
uint32_t num_nodes;
uint64_t first_start;
uint64_t first_end;
uint64_t last_end;
uint64_t ipbw_data[0];
}ip_bw_kernel_data_item;
typedef struct
{
uint8_t error;
uint32_t ip_total;
uint32_t index_start;
uint32_t ip_num;
uint64_t reset_interval;
uint64_t reset_time;
uint8_t reset_is_constant_interval;
/*payload for history ip bw data*/
ip_bw_kernel_data_item data_item[0];
}ip_bw_kernel_data;
typedef struct history_struct
{
uint32_t ip;
uint32_t num_nodes;
time_t reset_interval;
time_t reset_time;
unsigned char is_constant_interval;
time_t first_start;
time_t first_end;
time_t last_end;
uint64_t* history_bws;
} ip_bw_history;
#pragma pack(pop)
time_t* get_interval_starts_for_history(ip_bw_history history);
extern void free_ip_bw_histories(ip_bw_history* histories, int num_histories);
extern int get_all_bandwidth_history_for_rule_id(char* id, unsigned long* num_ips, ip_bw_history** data, unsigned long max_wait_milliseconds);
extern int get_ip_bandwidth_history_for_rule_id(char* id, char* ip, ip_bw_history** data, unsigned long max_wait_milliseconds);
extern int get_all_bandwidth_usage_for_rule_id(char* id, unsigned long* num_ips, ip_bw** data, unsigned long max_wait_milliseconds);
extern int get_ip_bandwidth_usage_for_rule_id(char* id, char* ip, ip_bw** data, unsigned long max_wait_milliseconds);
extern int set_bandwidth_history_for_rule_id(char* id, unsigned char zero_unset, unsigned long num_ips, ip_bw_history* data, unsigned long max_wait_milliseconds);
extern int set_bandwidth_usage_for_rule_id(char* id, unsigned char zero_unset, unsigned long num_ips, time_t last_backup, ip_bw* data, unsigned long max_wait_milliseconds);
extern int save_usage_to_file(ip_bw* data, unsigned long num_ips, char* out_file_path);
extern int save_history_to_file(ip_bw_history* data, unsigned long num_ips, char* out_file_path);
extern ip_bw* load_usage_from_file(char* in_file_path, unsigned long* num_ips, time_t* last_backup);
extern ip_bw_history* load_history_from_file(char* in_file_path, unsigned long* num_ips);
extern void print_usage(FILE* out, ip_bw* usage, unsigned long num_ips);
extern void print_histories(FILE* out, char* id, ip_bw_history* histories, unsigned long num_histories, char output_type);
extern void unlock_bandwidth_semaphore(void);
extern void unlock_bandwidth_semaphore_on_exit(void);
/* sets kernel timezone minuteswest to match user timezone */
extern int get_minutes_west(time_t now);
extern void set_kernel_timezone(void);
/* safe malloc & strdup functions used to handle malloc errors cleanly */
extern void* ipt_bwctl_safe_malloc(size_t size);
extern char* ipt_bwctl_safe_strdup(const char* str);

View File

@ -1,23 +0,0 @@
#include "ipt_bwctl.h"
void *ipt_bwctl_safe_malloc(size_t size)
{
void* val = malloc(size);
if(val == NULL)
{
fprintf(stderr, "ERROR: MALLOC FAILURE!\n");
exit(1);
}
return val;
}
char* ipt_bwctl_safe_strdup(const char* str)
{
char* new_str = strdup(str);
if(new_str == NULL)
{
fprintf(stderr, "ERROR: MALLOC FAILURE!\n");
exit(1);
}
return new_str;
}

View File

@ -1,12 +0,0 @@
all: bw_set bw_get bw_print_history_file set_kernel_timezone
bw_set: bw_set.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -liptbwctl
bw_get: bw_get.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -liptbwctl
bw_print_history_file: bw_print_history_file.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -liptbwctl
set_kernel_timezone: set_kernel_timezone.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -liptbwctl
clean:
rm -rf bw_set bw_get print_history_file set_kernel_timezone *.o *~ .*sw*

View File

@ -1,177 +0,0 @@
/* libiptbwctl -- A userspace library for querying the bandwidth iptables module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <ipt_bwctl.h>
#define malloc ipt_bwctl_safe_malloc
#define strdup ipt_bwctl_safe_strdup
int main(int argc, char **argv)
{
char *id = NULL;
char* out_file_path = NULL;;
char *address = NULL;
unsigned long num_ips;
void *ip_buf;
unsigned long out_index;
int query_succeeded;
int get_history = 0;
char output_type = 'h';
int c;
struct in_addr read_addr;
while((c = getopt(argc, argv, "i:I:a:A:f:F:tThHmMuU")) != -1)
{
switch(c)
{
case 'i':
case 'I':
if(strlen(optarg) < BANDWIDTH_MAX_ID_LENGTH && strlen(optarg) > 0)
{
id = strdup(optarg);
}
else
{
fprintf(stderr, "ERROR: ID length is improper length.\n");
exit(0);
}
break;
case 'a':
case 'A':
if(strcmp(optarg, "combined") == 0 || strcmp(optarg, "COMBINED") == 0)
{
address = strdup("0.0.0.0");
}
else if( inet_aton(optarg, &read_addr) )
{
address = strdup(optarg);
}
else
{
fprintf(stderr, "ERROR: invalid IP address specified\n");
exit(0);
}
break;
case 'f':
case 'F':
out_file_path = strdup(optarg);
break;
case 'h':
case 'H':
get_history = 1;
break;
case 'm':
case 'M':
output_type = 'm';
break;
case 't':
case 'T':
output_type = 't';
break;
case 'u':
case 'U':
default:
fprintf(stderr, "USAGE:\n\t%s -i [ID] -a [IP ADDRESS] -f [OUT_FILE_NAME]\n", argv[0]);
exit(0);
}
}
if(id == NULL)
{
fprintf(stderr, "ERROR: you must specify an id to query\n\n");
exit(0);
}
set_kernel_timezone();
unlock_bandwidth_semaphore_on_exit();
if(get_history == 0)
{
if(address == NULL)
{
query_succeeded = get_all_bandwidth_usage_for_rule_id(id, &num_ips, (ip_bw**)&ip_buf, 1000);
}
else
{
num_ips = 1;
query_succeeded = get_ip_bandwidth_usage_for_rule_id(id, address, (ip_bw**)&ip_buf, 1000);
}
}
else
{
if(address == NULL)
{
query_succeeded = get_all_bandwidth_history_for_rule_id(id, &num_ips, (ip_bw_history**)&ip_buf, 1000);
}
else
{
num_ips = 1;
query_succeeded = get_ip_bandwidth_history_for_rule_id(id, address, (ip_bw_history**)&ip_buf, 1000);
}
}
if(!query_succeeded)
{
fprintf(stderr, "ERROR: Bandwidth query failed, make sure rule with specified id exists, and that you are performing only one query at a time.\n\n");
exit(0);
}
if(out_file_path != NULL)
{
if(get_history == 0)
{
save_usage_to_file( (ip_bw*)ip_buf, num_ips, out_file_path);
}
else
{
save_history_to_file( (ip_bw_history*)ip_buf, num_ips, out_file_path);
}
}
else
{
if(get_history == 0)
{
print_usage(stdout, (ip_bw*)ip_buf, num_ips);
}
else
{
print_histories(stdout, id, (ip_bw_history*)ip_buf, num_ips, output_type );
}
}
if(num_ips == 0)
{
if(output_type != 't' && output_type != 'm')
{
fprintf(stderr, "No data available for id \"%s\"\n", id);
}
}
printf("\n");
if(out_file_path != NULL)
{
free(out_file_path);
}
return 0;
}

View File

@ -1,39 +0,0 @@
/* libiptbwctl -- A userspace library for querying the bandwidth iptables module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <ipt_bwctl.h>
#define malloc ipt_bwctl_safe_malloc
#define strdup ipt_bwctl_safe_strdup
int main(int argc, char **argv)
{
if(argc > 1)
{
unsigned long num_ips;
ip_bw_history* histories = load_history_from_file(argv[1], &num_ips);
if(histories != NULL)
{
print_histories(stdout, argv[1], histories, num_ips, 'h');
}
}
return 0;
}

View File

@ -1,186 +0,0 @@
/* libiptbwctl -- A userspace library for querying the bandwidth iptables module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <ipt_bwctl.h>
#define malloc ipt_bwctl_safe_malloc
#define strdup ipt_bwctl_safe_strdup
static char* read_entire_file(FILE* in, int read_block_size);
static char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long *pieces_read);
int main(int argc, char **argv)
{
char *id = NULL;
char* in_file_path = NULL;
FILE* in_file = NULL;
time_t last_backup = 0;
int last_backup_from_cl = 0;
int is_history_file = 0;
int c;
while((c = getopt(argc, argv, "i:I:b:B:f:F:UuHh")) != -1)
{
switch(c)
{
case 'i':
case 'I':
if(strlen(optarg) < BANDWIDTH_MAX_ID_LENGTH)
{
id = strdup(optarg);
}
else
{
fprintf(stderr, "ERROR: ID length is improper length.\n");
exit(0);
}
break;
case 'b':
case 'B':
if(sscanf(optarg, "%ld", &last_backup) == 0)
{
fprintf(stderr, "ERROR: invalid backup time specified. Should be unix epoch seconds -- number of seconds since 1970 (UTC)\n");
exit(0);
}
last_backup_from_cl = 1;
break;
case 'f':
case 'F':
in_file_path = strdup(optarg);
in_file = fopen(optarg, "rb");
if(in_file == NULL)
{
fprintf(stderr, "ERROR: cannot open specified file for reading\n");
exit(0);
}
fclose(in_file);
break;
case 'h':
case 'H':
is_history_file = 1;
break;
case 'u':
case 'U':
default:
fprintf(stderr, "USAGE:\n\t%s -i [ID] -b [LAST_BACKUP_TIME] -f [IN_FILE_NAME] [ IP BANDWIDTH PAIRS, IF -f NOT SPECIFIED ]\n", argv[0]);
exit(0);
}
}
if(id == NULL)
{
fprintf(stderr, "ERROR: you must specify an id for which to set data\n\n");
exit(0);
}
if(in_file_path == NULL && is_history_file)
{
fprintf(stderr, "ERROR: you need to specify file to load history from\n\t\t(history format is too complex to load from command line)\n");
}
set_kernel_timezone();
unlock_bandwidth_semaphore_on_exit();
int query_succeeded = 0;
if(in_file_path != NULL)
{
if(is_history_file)
{
unsigned long num_ips;
ip_bw_history* history_data = load_history_from_file(in_file_path, &num_ips);
if(history_data != NULL)
{
query_succeeded = set_bandwidth_history_for_rule_id(id, 1, num_ips, history_data, 1000);
}
}
else
{
unsigned long num_ips;
time_t last_backup;
ip_bw* usage_data = load_usage_from_file(in_file_path, &num_ips, &last_backup);
if(usage_data != NULL)
{
query_succeeded = set_bandwidth_usage_for_rule_id(id, 1, num_ips, last_backup, usage_data, 1000);
}
}
}
else
{
char** data_parts;
unsigned long num_data_parts;
data_parts = argv+optind;
num_data_parts = argc - optind;
unsigned long num_ips = num_data_parts/2;
ip_bw* buffer = (ip_bw*)malloc(num_ips*sizeof(ip_bw));
unsigned long data_index = 0;
unsigned long buffer_index = 0;
while(data_index < num_data_parts)
{
ip_bw next;
struct in_addr ipaddr;
int valid = inet_aton(data_parts[data_index], &ipaddr);
if((!valid) && (!last_backup_from_cl))
{
sscanf(data_parts[data_index], "%ld", &last_backup);
}
data_index++;
if(valid && data_index < num_data_parts)
{
next.ip = ipaddr.s_addr;
valid = sscanf(data_parts[data_index], "%lld", (long long int*)&(next.bw) );
data_index++;
}
else
{
valid = 0;
}
if(valid)
{
/* printf("ip=%d, bw=%lld\n", next.ip, (long long int)next.bw); */
buffer[buffer_index] = next;
buffer_index++;
}
}
num_ips = buffer_index; /* number that were successfully read */
query_succeeded = set_bandwidth_usage_for_rule_id(id, 1, num_ips, last_backup, buffer, 1000);
}
if(!query_succeeded)
{
fprintf(stderr, "ERROR: Could not set data. Please try again.\n\n");
}
else
{
fprintf(stderr, "Data set successfully\n\n");
}
if(in_file_path != NULL)
{
free(in_file_path);
}
return 0;
}

View File

@ -1,27 +0,0 @@
/* libiptbwctl -- A userspace library for querying the bandwidth iptables module
* Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
*
*
* Copyright © 2009 by Eric Bishop <eric@gargoyle-router.com>
*
* This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
*/
#include <ipt_bwctl.h>
int main(void)
{
set_kernel_timezone();
return 0;
}

View File

@ -1,22 +0,0 @@
#
# Copyright (C) 2017 Xingwang Liao <kuoruan@gmail.com>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-qos-gargoyle
PKG_VERSION:=1.3.6
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Xingwang Liao <kuoruan@gmail.com>
LUCI_TITLE:=LuCI Support for Gargoyle QoS
LUCI_DEPENDS:=+qos-gargoyle
LUCI_PKGARCH:=all
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -1,100 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.qos_gargoyle", package.seeall)
local util = require "luci.util"
local http = require "luci.http"
function index()
if not nixio.fs.access("/etc/config/qos_gargoyle") then
return
end
entry({"admin", "network", "qos_gargoyle"},
firstchild(), _("Gargoyle QoS"), 60)
entry({"admin", "network", "qos_gargoyle", "global"},
cbi("qos_gargoyle/global"), _("Global Settings"), 10)
entry({"admin", "network", "qos_gargoyle", "upload"},
cbi("qos_gargoyle/upload"), _("Upload Settings"), 20)
entry({"admin", "network", "qos_gargoyle", "upload", "class"},
cbi("qos_gargoyle/upload_class")).leaf = true
entry({"admin", "network", "qos_gargoyle", "upload", "rule"},
cbi("qos_gargoyle/upload_rule")).leaf = true
entry({"admin", "network", "qos_gargoyle", "download"},
cbi("qos_gargoyle/download"), _("Download Settings"), 30)
entry({"admin", "network", "qos_gargoyle", "download", "class"},
cbi("qos_gargoyle/download_class")).leaf = true
entry({"admin", "network", "qos_gargoyle", "download", "rule"},
cbi("qos_gargoyle/download_rule")).leaf = true
entry({"admin", "network", "qos_gargoyle", "troubleshooting"},
template("qos_gargoyle/troubleshooting"), _("Troubleshooting"), 40)
entry({"admin", "network", "qos_gargoyle", "troubleshooting", "data"},
call("action_troubleshooting_data"))
entry({"admin", "network", "qos_gargoyle", "load_data"},
call("action_load_data")).leaf = true
end
function action_troubleshooting_data()
local uci = require "luci.model.uci".cursor()
local i18n = require "luci.i18n"
local data = {}
local monenabled = uci:get("qos_gargoyle", "download", "qos_monenabled") or "false"
local show_data = util.trim(util.exec("/etc/init.d/qos_gargoyle show 2>/dev/null"))
if show_data == "" then
show_data = i18n.translate("No data found")
end
data.show = show_data
local mon_data
if monenabled == "true" then
mon_data = util.trim(util.exec("cat /tmp/qosmon.status 2>/dev/null"))
if mon_data == "" then
mon_data = i18n.translate("No data found")
end
else
mon_data = i18n.translate("\"Active Congestion Control\" not enabled")
end
data.mon = mon_data
http.prepare_content("application/json")
http.write_json(data)
end
function action_load_data(type)
local device
if type == "download" then
device = "imq0"
elseif type == "upload" then
local qos = require "luci.model.qos_gargoyle"
local wan = qos.get_wan()
device = wan and wan:ifname() or ""
end
if device then
local data
if device ~= "" then
data = util.exec("tc -s class show dev %s 2>/dev/null" % device)
end
http.prepare_content("text/plain")
http.write(data or "")
else
http.status(500, "Bad address")
end
end

View File

@ -1,166 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local dsp = require "luci.dispatcher"
local http = require "luci.http"
local qos = require "luci.model.qos_gargoyle"
local m, class_s, rule_s, o
local download_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "download_class", function(s)
local class_alias = s.name
if class_alias then
download_classes[#download_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Download Settings"))
m.template = "qos_gargoyle/list_view"
class_s = m:section(TypedSection, "download_class", translate("Service Classes"),
translate("Each service class is specified by four parameters: percent bandwidth at capacity, "
.. "realtime bandwidth and maximum bandwidth and the minimimze round trip time flag."))
class_s.anonymous = true
class_s.addremove = true
class_s.template = "cbi/tblsection"
class_s.extedit = dsp.build_url("admin/network/qos_gargoyle/download/class/%s")
class_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(class_s.extedit % sid)
return
end
end
o = class_s:option(DummyValue, "name", translate("Class Name"))
o.cfgvalue = function(...)
return Value.cfgvalue(...) or translate("None")
end
o = class_s:option(DummyValue, "percent_bandwidth", translate("Percent Bandwidth At Capacity"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return "%d %%" % v
end
return translate("Not set")
end
o = class_s:option(DummyValue, "min_bandwidth", "%s (kbps)" % translate("Minimum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Zero")
end
o = class_s:option(DummyValue, "max_bandwidth", "%s (kbps)" % translate("Maximum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Unlimited")
end
o = class_s:option(DummyValue, "minRTT", translate("Minimize RTT"))
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and translate(v) or translate("No")
end
o = class_s:option(DummyValue, "_ld", "%s (kbps)" % translate("Load"))
o.rawhtml = true
o.value = "<em class=\"ld-download\">*</em>"
rule_s = m:section(TypedSection, "download_rule", translate("Classification Rules"),
translate("Packets are tested against the rules in the order specified -- rules toward the top "
.. "have priority. As soon as a packet matches a rule it is classified, and the rest of the rules "
.. "are ignored. The order of the rules can be altered using the arrow controls.")
)
rule_s.addremove = true
rule_s.sortable = true
rule_s.anonymous = true
rule_s.template = "cbi/tblsection"
rule_s.extedit = dsp.build_url("admin/network/qos_gargoyle/download/rule/%s")
rule_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(rule_s.extedit % sid)
return
end
end
o = rule_s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(download_classes) do o:value(s.name, s.alias) end
o = rule_s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.size = "10"
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or ""
end
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = rule_s:option(Value, "source", translate("Source IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "srcport", translate("Source Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(Value, "destination", translate("Destination IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "dstport", translate("Destination Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(DummyValue, "min_pkt_size", translate("Minimum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "max_pkt_size", translate("Maximum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "connbytes_kb", translate("Connection Bytes Reach"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v * 1024)
end
return translate("Not set")
end
if qos.has_ndpi() then
o = rule_s:option(DummyValue, "ndpi", translate("DPI Protocol"))
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or translate("All")
end
end
return m

View File

@ -1,61 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local m, s, o
local sid = arg[1]
local qos_gargoyle = "qos_gargoyle"
m = Map(qos_gargoyle, translate("Edit Download Service Class"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/download")
if m.uci:get(qos_gargoyle, sid) ~= "download_class" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "download_class")
s.anonymous = true
s.addremove = false
o = s:option(Value, "name", translate("Service Class Name"))
o.rmempty = false
o = s:option(Value, "percent_bandwidth", translate("Percent Bandwidth At Capacity"),
translate("The percentage of the total available bandwidth that should be allocated to this class "
.. "when all available bandwidth is being used. If unused bandwidth is available, more can (and "
.. "will) be allocated. The percentages can be configured to equal more (or less) than 100, but "
.. "when the settings are applied the percentages will be adjusted proportionally so that they "
.. "add to 100. This setting only comes into effect when the WAN link is saturated."))
o.datatype = "range(1, 100)"
o.rmempty = false
o = s:option(Value, "min_bandwidth", translate("Minimum Bandwidth"),
translate("The minimum service this class will be allocated when the link is at capacity. Classes "
.. "which specify minimum service are known as realtime classes by the active congestion "
.. "controller. Streaming video, VoIP and interactive online gaming are all examples of "
.. "applications that must have a minimum bandwith to function. To determine what to enter use "
.. "the application on an unloaded LAN and observe how much bandwidth it uses. Then enter a "
.. "number only slightly higher than this into this field. QoS will satisfiy the minimum service "
.. "of all classes first before allocating to other waiting classes so be careful to use minimum "
.. "bandwidths sparingly."))
o:value("0", translate("Zero"))
o.datatype = "uinteger"
o.default = "0"
o = s:option(Value, "max_bandwidth", translate("Maximum Bandwidth"),
translate("The maximum amount of bandwidth this class will be allocated in kbit/s. Even if unused "
.. "bandwidth is available, this service class will never be permitted to use more than this "
.. "amount of bandwidth."))
o:value("", translate("Unlimited"))
o.datatype = "uinteger"
o = s:option(Flag, "minRTT", translate("Minimize RTT"),
translate("Indicates to the active congestion controller that you wish to minimize round trip "
.. "times (RTT) when this class is active. Use this setting for online gaming or VoIP "
.. "applications that need low round trip times (ping times). Minimizing RTT comes at the expense "
.. "of efficient WAN throughput so while these class are active your WAN throughput will decline "
.. "(usually around 20%)."))
o.enabled = "Yes"
o.disabled = "No"
return m

View File

@ -1,87 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local qos = require "luci.model.qos_gargoyle"
local m, s, o
local sid = arg[1]
local download_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "download_class", function(s)
local class_alias = s.name
if class_alias then
download_classes[#download_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Edit Download Classification Rule"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/download")
if m.uci:get(qos_gargoyle, sid) ~= "download_rule" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "download_rule")
s.anonymous = true
s.addremove = false
o = s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(download_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = s:option(Value, "source", translate("Source IP(s)"),
translate("Packet's source ip, can optionally have /[mask] after it (see -s option in iptables "
.. "man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "srcport", translate("Source Port(s)"),
translate("Packet's source port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "destination", translate("Destination IP(s)"),
translate("Packet's destination ip, can optionally have /[mask] after it (see -d option in "
.. "iptables man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "dstport", translate("Destination Port(s)"),
translate("Packet's destination port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "min_pkt_size", translate("Minimum Packet Length"),
translate("Packet's minimum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "max_pkt_size", translate("Maximum Packet Length"),
translate("Packet's maximum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "connbytes_kb", translate("Connection Bytes Reach"),
translate("The total size of data transmitted since the establishment of the link (in kBytes)."))
o.datatype = "range(0, 4194303)"
if qos.has_ndpi() then
o = s:option(ListValue, "ndpi", translate("DPI Protocol"))
o:value("", translate("All"))
qos.cbi_add_dpi_protocols(o)
end
return m

View File

@ -1,124 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local sys = require "luci.sys"
local uci = require "luci.model.uci".cursor()
local net = require "luci.model.network".init()
local qos = require "luci.model.qos_gargoyle"
local m, s, o
local upload_classes = {}
local download_classes = {}
local qos_gargoyle = "qos_gargoyle"
local function qos_enabled()
return sys.init.enabled(qos_gargoyle)
end
uci:foreach(qos_gargoyle, "upload_class", function(s)
local class_alias = s.name
if class_alias then
upload_classes[#upload_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
uci:foreach(qos_gargoyle, "download_class", function(s)
local class_alias = s.name
if class_alias then
download_classes[#download_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Gargoyle QoS"),
translate("Quality of Service (QoS) provides a way to control how available bandwidth is "
.. "allocated."))
s = m:section(TypedSection, 'global', translate("Global Settings"))
s.anonymous = true
o = s:option(Button, "", translate("QoS Switch"))
o.render = function(self, section, scope)
if qos_enabled() then
self.title = translate("Disable QoS")
self.inputstyle = "reset"
else
self.title = translate("Enable QoS")
self.inputstyle = "apply"
end
Button.render(self, section, scope)
end
o.write = function(...)
if qos_enabled() then
sys.init.stop(qos_gargoyle)
sys.init.disable(qos_gargoyle)
else
sys.init.enable(qos_gargoyle)
sys.init.start(qos_gargoyle)
end
end
s = m:section(NamedSection, "upload", "upload", translate("Upload Settings"))
s.anonymous = true
o = s:option(ListValue, "default_class", translate("Default Service Class"),
translate("Specifie how packets that do not match any rule should be classified."))
for _, s in ipairs(upload_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "total_bandwidth", translate("Total Upload Bandwidth"),
translate("Should be set to around 98% of your available upload bandwidth. Entering a number "
.. "which is too high will result in QoS not meeting its class requirements. Entering a number "
.. "which is too low will needlessly penalize your upload speed. You should use a speed test "
.. "program (with QoS off) to determine available upload bandwidth. Note that bandwidth is "
.. "specified in kbps, leave blank to disable update QoS. There are 8 kilobits per kilobyte."))
o.datatype = "uinteger"
s = m:section(NamedSection, "download", "download", translate("Download Settings"))
s.anonymous = true
o = s:option(ListValue, "default_class", translate("Default Service Class"),
translate("Specifie how packets that do not match any rule should be classified."))
for _, s in ipairs(download_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "total_bandwidth", translate("Total Download Bandwidth"),
translate("Specifying correctly is crucial to making QoS work. Note that bandwidth is specified "
.. "in kbps, leave blank to disable download QoS. There are 8 kilobits per kilobyte."))
o.datatype = "uinteger"
o = s:option(Flag, "qos_monenabled", translate("Enable Active Congestion Control"),
translate("<p>The active congestion control (ACC) observes your download activity and "
.. "automatically adjusts your download link limit to maintain proper QoS performance. ACC "
.. "automatically compensates for changes in your ISP's download speed and the demand from your "
.. "network adjusting the link speed to the highest speed possible which will maintain proper QoS "
.. "function. The effective range of this control is between 15% and 100% of the total download "
.. "bandwidth you entered above.</p>") ..
translate("<p>While ACC does not adjust your upload link speed you must enable and properly "
.. "configure your upload QoS for it to function properly.</p>")
)
o.enabled = "true"
o.disabled = "false"
o = s:option(Value, "ptarget_ip", translate("Use Non-standard Ping Target"),
translate("The segment of network between your router and the ping target is where congestion is "
.. "controlled. By monitoring the round trip ping times to the target congestion is detected. By "
.. "default ACC uses your WAN gateway as the ping target. If you know that congestion on your "
.. "link will occur in a different segment then you can enter an alternate ping target. Leave "
.. "empty to use the default settings."))
o:depends("qos_monenabled", "true")
-- local wan = qos.get_wan()
-- if wan then o:value(wan:gwaddr()) end
-- TODO: get wan address
o.datatype = "ipaddr"
o = s:option(Value, "pinglimit", translate("Manual Ping Limit"),
translate("Round trip ping times are compared against the ping limits. ACC controls the link "
.. "limit to maintain ping times under the appropriate limit. By default ACC attempts to "
.. "automatically select appropriate target ping limits for you based on the link speeds you "
.. "entered and the performance of your link it measures during initialization. You cannot change "
.. "the target ping time for the minRTT mode but by entering a manual time you can control the "
.. "target ping time of the active mode. The time you enter becomes the increase in the target "
.. "ping time between minRTT and active mode. Leave empty to use the default settings."))
o:depends("qos_monenabled", "true")
o:value("Auto", translate("Auto"))
o.datatype = "or('Auto', range(10, 250))"
return m

View File

@ -1,160 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local dsp = require "luci.dispatcher"
local http = require "luci.http"
local qos = require "luci.model.qos_gargoyle"
local m, class_s, rule_s, o
local upload_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "upload_class", function(s)
local class_alias = s.name
if class_alias then
upload_classes[#upload_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Upload Settings"))
m.template = "qos_gargoyle/list_view"
class_s = m:section(TypedSection, "upload_class", translate("Service Classes"),
translate("Each upload service class is specified by three parameters: percent bandwidth at "
.. "capacity, minimum bandwidth and maximum bandwidth."))
class_s.anonymous = true
class_s.addremove = true
class_s.template = "cbi/tblsection"
class_s.extedit = dsp.build_url("admin/network/qos_gargoyle/upload/class/%s")
class_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(class_s.extedit % sid)
return
end
end
o = class_s:option(DummyValue, "name", translate("Class Name"))
o.cfgvalue = function(...)
return Value.cfgvalue(...) or translate("None")
end
o = class_s:option(DummyValue, "percent_bandwidth", translate("Percent Bandwidth At Capacity"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return "%d %%" % v
end
return translate("Not set")
end
o = class_s:option(DummyValue, "min_bandwidth", "%s (kbps)" % translate("Minimum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Zero")
end
o = class_s:option(DummyValue, "max_bandwidth", "%s (kbps)" % translate("Maximum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Unlimited")
end
o = class_s:option(DummyValue, "_ld", "%s (kbps)" % translate("Load"))
o.rawhtml = true
o.value = "<em class=\"ld-upload\">*</em>"
rule_s = m:section(TypedSection, "upload_rule",translate("Classification Rules"),
translate("Packets are tested against the rules in the order specified -- rules toward the top "
.. "have priority. As soon as a packet matches a rule it is classified, and the rest of the rules "
.. "are ignored. The order of the rules can be altered using the arrow controls.")
)
rule_s.addremove = true
rule_s.sortable = true
rule_s.anonymous = true
rule_s.template = "cbi/tblsection"
rule_s.extedit = dsp.build_url("admin/network/qos_gargoyle/upload/rule/%s")
rule_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(rule_s.extedit % sid)
return
end
end
o = rule_s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(upload_classes) do o:value(s.name, s.alias) end
o = rule_s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.size = "10"
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or ""
end
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = rule_s:option(Value, "source", translate("Source IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "srcport", translate("Source Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(Value, "destination", translate("Destination IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "dstport", translate("Destination Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(DummyValue, "min_pkt_size", translate("Minimum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "max_pkt_size", translate("Maximum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "connbytes_kb", translate("Connection Bytes Reach"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v * 1024)
end
return translate("Not set")
end
if qos.has_ndpi() then
o = rule_s:option(DummyValue, "ndpi", translate("DPI Protocol"))
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or translate("All")
end
end
return m

View File

@ -1,52 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local m, s, o
local sid = arg[1]
local qos_gargoyle = "qos_gargoyle"
m = Map(qos_gargoyle, translate("Edit Upload Service Class"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/upload")
if m.uci:get(qos_gargoyle, sid) ~= "upload_class" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "upload_class")
s.anonymous = true
s.addremove = false
o = s:option(Value, "name", translate("Service Class Name"))
o.rmempty = false
o = s:option(Value, "percent_bandwidth", translate("Percent Bandwidth At Capacity"),
translate("The percentage of the total available bandwidth that should be allocated to this class "
.. "when all available bandwidth is being used. If unused bandwidth is available, more can (and "
.. "will) be allocated. The percentages can be configured to equal more (or less) than 100, but "
.. "when the settings are applied the percentages will be adjusted proportionally so that they "
.. "add to 100. This setting only comes into effect when the WAN link is saturated."))
o.datatype = "range(1, 100)"
o.rmempty = false
o = s:option(Value, "min_bandwidth", translate("Minimum Bandwidth"),
translate("The minimum service this class will be allocated when the link is at capacity. Classes "
.. "which specify minimum service are known as realtime classes by the active congestion "
.. "controller. Streaming video, VoIP and interactive online gaming are all examples of "
.. "applications that must have a minimum bandwith to function. To determine what to enter use "
.. "the application on an unloaded LAN and observe how much bandwidth it uses. Then enter a "
.. "number only slightly higher than this into this field. QoS will satisfiy the minimum service "
.. "of all classes first before allocating to other waiting classes so be careful to use minimum "
.. "bandwidths sparingly."))
o:value("0", translate("Zero"))
o.datatype = "uinteger"
o.default = "0"
o = s:option(Value, "max_bandwidth", translate("Maximum Bandwidth"),
translate("The maximum amount of bandwidth this class will be allocated in kbit/s. Even if unused "
.. "bandwidth is available, this service class will never be permitted to use more than this "
.. "amount of bandwidth."))
o:value("", translate("Unlimited"))
o.datatype = "uinteger"
return m

View File

@ -1,87 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local qos = require "luci.model.qos_gargoyle"
local m, s, o
local sid = arg[1]
local upload_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "upload_class", function(s)
local class_alias = s.name
if class_alias then
upload_classes[#upload_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Edit Upload Classification Rule"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/upload")
if m.uci:get(qos_gargoyle, sid) ~= "upload_rule" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "upload_rule")
s.anonymous = true
s.addremove = false
o = s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(upload_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = s:option(Value, "source", translate("Source IP(s)"),
translate("Packet's source ip, can optionally have /[mask] after it (see -s option in iptables "
.. "man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "srcport", translate("Source Port(s)"),
translate("Packet's source port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "destination", translate("Destination IP(s)"),
translate("Packet's destination ip, can optionally have /[mask] after it (see -d option in "
.. "iptables man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "dstport", translate("Destination Port(s)"),
translate("Packet's destination port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "min_pkt_size", translate("Minimum Packet Length"),
translate("Packet's minimum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "max_pkt_size", translate("Maximum Packet Length"),
translate("Packet's maximum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "connbytes_kb", translate("Connection Bytes Reach"),
translate("The total size of data transmitted since the establishment of the link (in kBytes)."))
o.datatype = "range(0, 4194303)"
if qos.has_ndpi() then
o = s:option(ListValue, "ndpi", translate("DPI Protocol"))
o:value("", translate("All"))
qos.cbi_add_dpi_protocols(o)
end
return m

View File

@ -1,38 +0,0 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
module("luci.model.qos_gargoyle", package.seeall)
function has_ndpi()
return luci.sys.call("lsmod | cut -d ' ' -f1 | grep -q 'xt_ndpi'") == 0
end
function cbi_add_dpi_protocols(field)
local util = require "luci.util"
local dpi_protocols = {}
for line in util.execi("iptables -m ndpi --help 2>/dev/null | grep '^--'") do
local _, _, protocol, name = line:find("%-%-([^%s]+) Match for ([^%s]+)")
if protocol and name then
dpi_protocols[protocol] = name
end
end
for p, n in util.kspairs(dpi_protocols) do
field:value(p, n)
end
end
function get_wan()
local network = require "luci.model.network".init()
local bundle = network:get_status_by_route("0.0.0.0", 0)
local net, stat
for k, v in pairs(bundle) do
net = k
stat = v
break
end
return net and network:network(net, stat.proto)
end

View File

@ -1,97 +0,0 @@
<%#
Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
Licensed to the public under the Apache License 2.0.
-%>
<%
local dsp = require "luci.dispatcher"
local request = dsp.context.path
local leaf = request[#request]
-%>
<style title="text/css">
/* container for entire page. fixes bootstrap theme's ridiculously small page width */
.container {
max-width: none;
margin: 0 30px;
width: auto;
}
/* column for configuration section name */
table th {
padding: 5px 0;
text-align: center;
vertical-align: middle;
}
/* cells showing the configuration values */
table td {
padding: 5px 0;
text-align: center;
vertical-align: middle;
}
/* sort buttons column */
table.cbi-section-table td.cbi-section-table-cell {
text-align: center;
}
</style>
<%+cbi/map%>
<script type="text/javascript">//<![CDATA[
function bpsToKbpsString(bps) {
var kbps = '*';
var bpsn = parseInt(bps) / 1000;
if (isNaN(bpsn)) {
kbps = '*';
} else if (bpsn < 1) {
kbps = bpsn.toFixed(1) + '';
} else {
kbps = bpsn.toFixed(0) + '';
}
return kbps;
}
(function(doc){
var tbs = doc.getElementsByClassName('ld-<%=leaf%>');
var lastTime = 0;
var dataTable = [];
var updateInProgress = false;
XHR.poll(3, '<%=dsp.build_url("admin", "network", "qos_gargoyle", "load_data", leaf)%>',
null, function(res) {
if (res.readyState == 4 && tbs) {
var timestamp = new Date().getTime();
var timeDiff = timestamp - lastTime;
lastTime = timestamp;
if (updateInProgress) return;
updateInProgress = true;
var lines = res.responseText.match(/hfsc\s1:[0-9]{1,2}\s.+leaf.+\n.+Sent\s[0-9]+/g);
if (lines) {
for (var i = 0, len = lines.length; i < len; i++) {
var line = lines[i];
var idx = parseInt(line.match(/hfsc\s1:([0-9]+)/)[1]) - 2;
var lastBytes;
if (idx < tbs.length) {
lastBytes = dataTable[idx];
var newBytes = line.match(/Sent\s([0-9]+)/)[1];
dataTable[idx] = newBytes;
var bps = NaN;
if (lastBytes) {
var diffBytes = parseInt(newBytes) - parseInt(lastBytes);
if (diffBytes <= 0) {
bps = 0;
} else {
bps = diffBytes * 8000 / timeDiff;
}
}
tbs[idx].innerText = bpsToKbpsString(bps);
}
}
}
updateInProgress = false;
}
}
);
}(document));
//]]></script>

View File

@ -1,52 +0,0 @@
<%#
Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
Licensed to the public under the Apache License 2.0.
-%>
<% css = [[
#troubleshoot_text {
padding: 20px;
text-align: left;
}
#troubleshoot_text pre {
word-break: break-all;
margin: 0;
}
.description {
background-color: #33CCFF;
}
]]
-%>
<%+header%>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[
XHR.poll(15, '<%=url("admin/network/qos_gargoyle/troubleshooting/data")%>', null,
function(x, data) {
var tshoot = document.getElementById('troubleshoot_text');
if (data.hasOwnProperty("show")) {
tshoot.innerHTML = String.format(
'<pre>%s%s%s%s</pre>',
'<span class="description">Output of &#34;/etc/init.d/qos_gargoyle show&#34; : </span><br /><br />',
data.show,
'<br /><br /><span class="description">Output of &#34;cat /tmp/qosmon.status&#34; : </span><br /><br />',
data.mon
);
} else {
tshoot.innerHTML = '<strong><%:Error collecting troubleshooting information%></strong>';
}
}
);
//]]></script>
<div id="troubleshoot">
<fieldset class="cbi-section">
<legend><%:Troubleshooting Data%></legend>
<div id="troubleshoot_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
</fieldset>
</div>
<%+footer%>

View File

@ -1,514 +0,0 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: zh-Hans\n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
#: luasrc/controller/qos_gargoyle.lua:71
msgid "\"Active Congestion Control\" not enabled"
msgstr "“主动拥塞控制”未启用"
#: luasrc/model/cbi/qos_gargoyle/global.lua:88
msgid ""
"<p>The active congestion control (ACC) observes your download activity and "
"automatically adjusts your download link limit to maintain proper QoS "
"performance. ACC automatically compensates for changes in your ISP's "
"download speed and the demand from your network adjusting the link speed to "
"the highest speed possible which will maintain proper QoS function. The "
"effective range of this control is between 15% and 100% of the total "
"download bandwidth you entered above.</p>"
msgstr ""
"<p>主动拥塞控制系统ACC观察你的下载活动并自动调整你的下载链接限制以保持适"
"当的 QoS 性能。ACC 自动调整 QoS 功能以补偿来自你 ISP 的下载速度变化及来自你网"
"络链接速度的调整需求,使速度最大化。这个控制的有效范围在你上面输入的下载总带"
"宽的 15% 至 100% 之间。</p>"
#: luasrc/model/cbi/qos_gargoyle/global.lua:94
msgid ""
"<p>While ACC does not adjust your upload link speed you must enable and "
"properly configure your upload QoS for it to function properly.</p>"
msgstr ""
"<p>虽然 ACC 不调整你的上传链路速度,但你必须启用并正确配置你的上传 QoS 带宽以"
"使该功能正常工作。</p>"
#: luasrc/model/cbi/qos_gargoyle/download.lua:99
#: luasrc/model/cbi/qos_gargoyle/download.lua:114
#: luasrc/model/cbi/qos_gargoyle/download.lua:119
#: luasrc/model/cbi/qos_gargoyle/download.lua:123
#: luasrc/model/cbi/qos_gargoyle/download.lua:128
#: luasrc/model/cbi/qos_gargoyle/download.lua:162
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:36
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:48
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:54
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:60
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:66
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:83
#: luasrc/model/cbi/qos_gargoyle/upload.lua:93
#: luasrc/model/cbi/qos_gargoyle/upload.lua:108
#: luasrc/model/cbi/qos_gargoyle/upload.lua:113
#: luasrc/model/cbi/qos_gargoyle/upload.lua:117
#: luasrc/model/cbi/qos_gargoyle/upload.lua:122
#: luasrc/model/cbi/qos_gargoyle/upload.lua:156
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:36
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:48
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:54
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:60
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:66
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:83
msgid "All"
msgstr "全部"
#: luasrc/model/cbi/qos_gargoyle/global.lua:121
msgid "Auto"
msgstr "自动"
#: luasrc/model/cbi/qos_gargoyle/download.lua:40
#: luasrc/model/cbi/qos_gargoyle/upload.lua:40
msgid "Class Name"
msgstr "类型名称"
#: luasrc/model/cbi/qos_gargoyle/download.lua:76
#: luasrc/model/cbi/qos_gargoyle/upload.lua:70
msgid "Classification Rules"
msgstr "分类规则"
#: luasrc/view/qos_gargoyle/troubleshooting.htm:48
msgid "Collecting data..."
msgstr "正在收集数据..."
#: luasrc/model/cbi/qos_gargoyle/download.lua:149
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:77
#: luasrc/model/cbi/qos_gargoyle/upload.lua:143
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:77
msgid "Connection Bytes Reach"
msgstr "连接流量达到"
#: luasrc/model/cbi/qos_gargoyle/download.lua:159
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:82
#: luasrc/model/cbi/qos_gargoyle/upload.lua:153
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:82
msgid "DPI Protocol"
msgstr "DPI 协议"
#: luasrc/model/cbi/qos_gargoyle/global.lua:63
#: luasrc/model/cbi/qos_gargoyle/global.lua:78
msgid "Default Service Class"
msgstr "默认服务类型"
#: luasrc/model/cbi/qos_gargoyle/download.lua:122
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:57
#: luasrc/model/cbi/qos_gargoyle/upload.lua:116
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:57
msgid "Destination IP(s)"
msgstr "目标 IP"
#: luasrc/model/cbi/qos_gargoyle/download.lua:127
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:64
#: luasrc/model/cbi/qos_gargoyle/upload.lua:121
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:64
msgid "Destination Port(s)"
msgstr "目标端口"
#: luasrc/model/cbi/qos_gargoyle/global.lua:42
msgid "Disable QoS"
msgstr "禁用 QoS"
#: luasrc/controller/qos_gargoyle.lua:30
#: luasrc/model/cbi/qos_gargoyle/download.lua:21
#: luasrc/model/cbi/qos_gargoyle/global.lua:75
msgid "Download Settings"
msgstr "下载设置"
#: luasrc/model/cbi/qos_gargoyle/download.lua:25
msgid ""
"Each service class is specified by four parameters: percent bandwidth at "
"capacity, realtime bandwidth and maximum bandwidth and the minimimze round "
"trip time flag."
msgstr ""
"每个下载服务类型由四个参数指定:带宽占用百分比、最小保证带宽、最大带宽和最小"
"往返延时标志。"
#: luasrc/model/cbi/qos_gargoyle/upload.lua:25
msgid ""
"Each upload service class is specified by three parameters: percent "
"bandwidth at capacity, minimum bandwidth and maximum bandwidth."
msgstr "每个上传服务类型由三个参数指定:带宽占用百分比、最小带宽和最大带宽。"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:20
msgid "Edit Download Classification Rule"
msgstr "编辑下载分类规则"
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:8
msgid "Edit Download Service Class"
msgstr "编辑下载服务类型"
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:20
msgid "Edit Upload Classification Rule"
msgstr "编辑上传分类规则"
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:8
msgid "Edit Upload Service Class"
msgstr "编辑上传服务类型"
#: luasrc/model/cbi/qos_gargoyle/global.lua:87
msgid "Enable Active Congestion Control"
msgstr "启用主动拥塞控制"
#: luasrc/model/cbi/qos_gargoyle/global.lua:45
msgid "Enable QoS"
msgstr "启用 QoS"
#: luasrc/view/qos_gargoyle/troubleshooting.htm:39
msgid "Error collecting troubleshooting information"
msgstr "收集故障排查信息失败"
#: luasrc/controller/qos_gargoyle.lua:15
#: luasrc/model/cbi/qos_gargoyle/global.lua:32
msgid "Gargoyle QoS"
msgstr "石像鬼 QoS"
#: luasrc/controller/qos_gargoyle.lua:18
#: luasrc/model/cbi/qos_gargoyle/global.lua:36
msgid "Global Settings"
msgstr "全局设置"
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:53
msgid ""
"Indicates to the active congestion controller that you wish to minimize "
"round trip times (RTT) when this class is active. Use this setting for "
"online gaming or VoIP applications that need low round trip times (ping "
"times). Minimizing RTT comes at the expense of efficient WAN throughput so "
"while these class are active your WAN throughput will decline (usually "
"around 20%)."
msgstr ""
"告诉主动拥塞控制器你希望该服务类型启用时尽量减少往返延时RTT。该设置一般用"
"在 VoIP 或在线游戏这类需要低延时Ping 值的应用上。减小往返延时RTT会带"
"来WAN有效吞吐量的额外花销所以当这些服务类型启用时你的 WAN 吞吐量将下降(通"
"常在20%左右)"
#: luasrc/model/cbi/qos_gargoyle/download.lua:72
#: luasrc/model/cbi/qos_gargoyle/upload.lua:66
msgid "Load"
msgstr "负载"
#: luasrc/view/qos_gargoyle/troubleshooting.htm:48
msgid "Loading"
msgstr "正在加载"
#: luasrc/model/cbi/qos_gargoyle/global.lua:112
msgid "Manual Ping Limit"
msgstr "手动 Ping 限制"
#: luasrc/model/cbi/qos_gargoyle/download.lua:60
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:45
#: luasrc/model/cbi/qos_gargoyle/upload.lua:60
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:45
msgid "Maximum Bandwidth"
msgstr "最大带宽"
#: luasrc/model/cbi/qos_gargoyle/download.lua:140
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:73
#: luasrc/model/cbi/qos_gargoyle/upload.lua:134
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:73
msgid "Maximum Packet Length"
msgstr "最大数据包长度"
#: luasrc/model/cbi/qos_gargoyle/download.lua:66
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:52
msgid "Minimize RTT"
msgstr "最小往返延时"
#: luasrc/model/cbi/qos_gargoyle/download.lua:54
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:32
#: luasrc/model/cbi/qos_gargoyle/upload.lua:54
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:32
msgid "Minimum Bandwidth"
msgstr "最小带宽"
#: luasrc/model/cbi/qos_gargoyle/download.lua:131
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:69
#: luasrc/model/cbi/qos_gargoyle/upload.lua:125
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:69
msgid "Minimum Packet Length"
msgstr "最小数据包长度"
#: luasrc/model/cbi/qos_gargoyle/download.lua:69
msgid "No"
msgstr "否"
#: luasrc/controller/qos_gargoyle.lua:58 luasrc/controller/qos_gargoyle.lua:68
msgid "No data found"
msgstr "无数据"
#: luasrc/model/cbi/qos_gargoyle/download.lua:42
#: luasrc/model/cbi/qos_gargoyle/upload.lua:42
msgid "None"
msgstr "无"
#: luasrc/model/cbi/qos_gargoyle/download.lua:51
#: luasrc/model/cbi/qos_gargoyle/download.lua:137
#: luasrc/model/cbi/qos_gargoyle/download.lua:146
#: luasrc/model/cbi/qos_gargoyle/download.lua:155
#: luasrc/model/cbi/qos_gargoyle/upload.lua:51
#: luasrc/model/cbi/qos_gargoyle/upload.lua:131
#: luasrc/model/cbi/qos_gargoyle/upload.lua:140
#: luasrc/model/cbi/qos_gargoyle/upload.lua:149
msgid "Not set"
msgstr "未设置"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:58
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:58
msgid ""
"Packet's destination ip, can optionally have /[mask] after it (see -d option "
"in iptables man page)."
msgstr ""
"数据包的目标 IP可以在后面加子网掩码/[mask],请看 iptables 的 -d 参数说"
"明)"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:65
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:65
msgid "Packet's destination port, can be a range (eg. 80-90)."
msgstr "数据包的目标端口可以是一个范围例如80-90"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:74
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:74
msgid "Packet's maximum size (in bytes)."
msgstr "数据包的最大大小单位bytes"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:70
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:70
msgid "Packet's minimum size (in bytes)."
msgstr "数据包的最小大小单位bytes"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:46
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:46
msgid ""
"Packet's source ip, can optionally have /[mask] after it (see -s option in "
"iptables man page)."
msgstr ""
"数据包的源 IP可以在后面加子网掩码/[mask],请看 iptables 的 -s 参数说明)"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:53
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:53
msgid "Packet's source port, can be a range (eg. 80-90)."
msgstr "数据包的源端口可以是一个范围例如80-90"
#: luasrc/model/cbi/qos_gargoyle/download.lua:77
#: luasrc/model/cbi/qos_gargoyle/upload.lua:71
msgid ""
"Packets are tested against the rules in the order specified -- rules toward "
"the top have priority. As soon as a packet matches a rule it is classified, "
"and the rest of the rules are ignored. The order of the rules can be altered "
"using the arrow controls."
msgstr ""
"数据包将按规则中指定的顺序进行匹配 —— 靠上的规则优先进行匹配。一旦数据包匹配"
"一条规则那它将被归类,并且其余的规则将被忽略。使用上下箭头可调整规则的顺序。"
#: luasrc/model/cbi/qos_gargoyle/download.lua:45
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:23
#: luasrc/model/cbi/qos_gargoyle/upload.lua:45
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:23
msgid "Percent Bandwidth At Capacity"
msgstr "带宽占用百分比"
#: luasrc/model/cbi/qos_gargoyle/global.lua:39
msgid "QoS Switch"
msgstr "QoS 开关"
#: luasrc/model/cbi/qos_gargoyle/global.lua:33
msgid ""
"Quality of Service (QoS) provides a way to control how available bandwidth "
"is allocated."
msgstr "QoS 可以用来分配和控制可用带宽。"
#: luasrc/model/cbi/qos_gargoyle/global.lua:113
msgid ""
"Round trip ping times are compared against the ping limits. ACC controls the "
"link limit to maintain ping times under the appropriate limit. By default "
"ACC attempts to automatically select appropriate target ping limits for you "
"based on the link speeds you entered and the performance of your link it "
"measures during initialization. You cannot change the target ping time for "
"the minRTT mode but by entering a manual time you can control the target "
"ping time of the active mode. The time you enter becomes the increase in the "
"target ping time between minRTT and active mode. Leave empty to use the "
"default settings."
msgstr ""
"Ping 延时会与 Ping 限制进行比较。ACC 控制链路限制以保持 Ping 延时在适当范围。"
"默认情况下ACC 会自动根据你输入的链接适当为你选择适当的 Ping 限制。如果你想"
"尝试不同的 Ping 限制,你可以在这里输入一个时间值。输入高的时间值将导致更高的 "
"Ping 限制,低的时间值会有更低的限制。留空则将由 ACC 自动控制。"
#: luasrc/model/cbi/qos_gargoyle/download.lua:95
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:32
#: luasrc/model/cbi/qos_gargoyle/upload.lua:89
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:32
msgid "Service Class"
msgstr "服务类型"
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:20
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:20
msgid "Service Class Name"
msgstr "服务类型名称"
#: luasrc/model/cbi/qos_gargoyle/download.lua:24
#: luasrc/model/cbi/qos_gargoyle/upload.lua:24
msgid "Service Classes"
msgstr "服务类型"
#: luasrc/model/cbi/qos_gargoyle/global.lua:68
msgid ""
"Should be set to around 98% of your available upload bandwidth. Entering a "
"number which is too high will result in QoS not meeting its class "
"requirements. Entering a number which is too low will needlessly penalize "
"your upload speed. You should use a speed test program (with QoS off) to "
"determine available upload bandwidth. Note that bandwidth is specified in "
"kbps, leave blank to disable update QoS. There are 8 kilobits per kilobyte."
msgstr ""
"应被设置为你可用上传带宽的 98% 左右。输入数值太高将导致 QoS 不能匹配服务类型"
"的要求。输入数值太低将造成不必要的上传速度限制。你应当在 QoS 关闭的情况下使用"
"测速程序以确定可用的上传带宽。带宽以 kbps 为单位,留空以禁用上传 QoS。"
"1KByte/s=8Kbps"
#: luasrc/model/cbi/qos_gargoyle/download.lua:113
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:45
#: luasrc/model/cbi/qos_gargoyle/upload.lua:107
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:45
msgid "Source IP(s)"
msgstr "源 IP"
#: luasrc/model/cbi/qos_gargoyle/download.lua:118
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:52
#: luasrc/model/cbi/qos_gargoyle/upload.lua:112
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:52
msgid "Source Port(s)"
msgstr "源端口"
#: luasrc/model/cbi/qos_gargoyle/global.lua:64
#: luasrc/model/cbi/qos_gargoyle/global.lua:79
msgid "Specifie how packets that do not match any rule should be classified."
msgstr "指定当数据包不匹配任何规则时将被如何归类。"
#: luasrc/model/cbi/qos_gargoyle/global.lua:83
msgid ""
"Specifying correctly is crucial to making QoS work. Note that bandwidth is "
"specified in kbps, leave blank to disable download QoS. There are 8 kilobits "
"per kilobyte."
msgstr ""
"正确设置对于 QoS 的工作至关重要。带宽以 kbps 为单位,留空以禁用下载 QoS。"
"1KByte/s=8Kbps"
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:46
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:46
msgid ""
"The maximum amount of bandwidth this class will be allocated in kbit/s. Even "
"if unused bandwidth is available, this service class will never be permitted "
"to use more than this amount of bandwidth."
msgstr ""
"该服务类型可被分配的带宽最大值(以 kbit/s 为单位)。即使存在未使用带宽,该服"
"务类型也将永远不被允许使用超过此量的带宽。"
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:33
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:33
msgid ""
"The minimum service this class will be allocated when the link is at "
"capacity. Classes which specify minimum service are known as realtime "
"classes by the active congestion controller. Streaming video, VoIP and "
"interactive online gaming are all examples of applications that must have a "
"minimum bandwith to function. To determine what to enter use the application "
"on an unloaded LAN and observe how much bandwidth it uses. Then enter a "
"number only slightly higher than this into this field. QoS will satisfiy the "
"minimum service of all classes first before allocating to other waiting "
"classes so be careful to use minimum bandwidths sparingly."
msgstr ""
"将被分配用于该服务类型的最低链路带宽容量。指定了最小带宽的服务类型会被主动拥"
"塞控制器看作实时类应用。例如视频流、VoIP 和在线互动游戏都应该设置最小带宽。要"
"确定需要多少最小带宽,可以在一个没有负载的局域网中使用应用程序并观察它使用了"
"多少带宽。然后输入一个略高于这个值的数字到字段中。在分配剩余带宽到其它服务类"
"型前QoS 将优先满足所有服务类型的最小带宽要求,所以要谨慎地使用最小带宽。"
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:24
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:24
msgid ""
"The percentage of the total available bandwidth that should be allocated to "
"this class when all available bandwidth is being used. If unused bandwidth "
"is available, more can (and will) be allocated. The percentages can be "
"configured to equal more (or less) than 100, but when the settings are "
"applied the percentages will be adjusted proportionally so that they add to "
"100. This setting only comes into effect when the WAN link is saturated."
msgstr ""
"当所有可用带宽被占满后该服务类型占据总带宽的百分比。如果带宽未用完,该服务类"
"型会被分配更多带宽。该百分比值可被设置为等于、大于或小于 100但当设置被应用"
"时,百分比值将会被按比例调整以便使它们加起来等于 100。该设置只在 WAN 端链路饱"
"和时才生效。<em>PSWAN 端链路饱和即带宽被占用完)</em>"
#: luasrc/model/cbi/qos_gargoyle/global.lua:101
msgid ""
"The segment of network between your router and the ping target is where "
"congestion is controlled. By monitoring the round trip ping times to the "
"target congestion is detected. By default ACC uses your WAN gateway as the "
"ping target. If you know that congestion on your link will occur in a "
"different segment then you can enter an alternate ping target. Leave empty "
"to use the default settings."
msgstr ""
"在路由器和 Ping 目标之间的网络部分是拥塞控制的地方。拥塞通过监视和目标间的 "
"Ping 延时来检测。默认情况下 ACC 使用你的 WAN 网关作为 Ping 的目标。假如你知道"
"拥塞会在你链路的不同段发生,你可用输入一个备用的 Ping 目标。留空则将由ACC 自"
"动控制。"
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:78
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:78
msgid ""
"The total size of data transmitted since the establishment of the link (in "
"kBytes)."
msgstr "自连接建立以来传输的数据总量单位kBytes"
#: luasrc/model/cbi/qos_gargoyle/global.lua:82
msgid "Total Download Bandwidth"
msgstr "下载总带宽"
#: luasrc/model/cbi/qos_gargoyle/global.lua:67
msgid "Total Upload Bandwidth"
msgstr "上传总带宽"
#: luasrc/model/cbi/qos_gargoyle/download.lua:98
#: luasrc/model/cbi/qos_gargoyle/download_rule.lua:35
#: luasrc/model/cbi/qos_gargoyle/upload.lua:92
#: luasrc/model/cbi/qos_gargoyle/upload_rule.lua:35
msgid "Transport Protocol"
msgstr "协议"
#: luasrc/controller/qos_gargoyle.lua:39
msgid "Troubleshooting"
msgstr "故障排除"
#: luasrc/view/qos_gargoyle/troubleshooting.htm:47
msgid "Troubleshooting Data"
msgstr "故障排除数据"
#: luasrc/model/cbi/qos_gargoyle/download.lua:63
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:49
#: luasrc/model/cbi/qos_gargoyle/upload.lua:63
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:49
msgid "Unlimited"
msgstr "不限制"
#: luasrc/controller/qos_gargoyle.lua:21
#: luasrc/model/cbi/qos_gargoyle/global.lua:60
#: luasrc/model/cbi/qos_gargoyle/upload.lua:21
msgid "Upload Settings"
msgstr "上传设置"
#: luasrc/model/cbi/qos_gargoyle/global.lua:100
msgid "Use Non-standard Ping Target"
msgstr "使用自定义 Ping 目标"
#: luasrc/model/cbi/qos_gargoyle/download.lua:57
#: luasrc/model/cbi/qos_gargoyle/download_class.lua:41
#: luasrc/model/cbi/qos_gargoyle/upload.lua:57
#: luasrc/model/cbi/qos_gargoyle/upload_class.lua:41
msgid "Zero"
msgstr "零"

View File

@ -1,11 +0,0 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@qos_gargoyle[-1]
add ucitrack qos_gargoyle
set ucitrack.@qos_gargoyle[-1].init=qos_gargoyle
commit ucitrack
EOF
rm -rf /tmp/luci-modulecache /tmp/luci-indexcache
exit 0

View File

@ -1,11 +0,0 @@
{
"luci-app-qos-gargoyle": {
"description": "Grant UCI access for luci-app-qos-gargoyle",
"read": {
"uci": [ "qos_gargoyle" ]
},
"write": {
"uci": [ "qos_gargoyle" ]
}
}
}

View File

@ -195,26 +195,6 @@ iptables extension for IMQ support.
endef
define Package/iptables-mod-bandwidth
$(call Package/iptables/Module, +kmod-ipt-bandwidth)
TITLE:=bandwidth option extensions
endef
define Package/iptables-mod-timerange
$(call Package/iptables/Module, +kmod-ipt-timerange)
TITLE:=timerange option extensions
endef
define Package/iptables-mod-webmon
$(call Package/iptables/Module, +kmod-ipt-webmon)
TITLE:=webmon option extensions
endef
define Package/iptables-mod-weburl
$(call Package/iptables/Module, +kmod-ipt-weburl)
TITLE:=weburl option extensions
endef
define Package/iptables-mod-ipopt
$(call Package/iptables/Module, +kmod-ipt-ipopt)
TITLE:=IP/Packet option extensions
@ -712,10 +692,6 @@ $(eval $(call BuildPlugin,iptables-mod-physdev,$(IPT_PHYSDEV-m)))
$(eval $(call BuildPlugin,iptables-mod-filter,$(IPT_FILTER-m)))
$(eval $(call BuildPlugin,iptables-mod-cgroup,$(IPT_CGROUP-m)))
$(eval $(call BuildPlugin,iptables-mod-imq,$(IPT_IMQ-m)))
$(eval $(call BuildPlugin,iptables-mod-bandwidth,$(IPT_BANDWIDTH-m)))
$(eval $(call BuildPlugin,iptables-mod-timerange,$(IPT_TIMERANGE-m)))
$(eval $(call BuildPlugin,iptables-mod-webmon,$(IPT_WEBMON-m)))
$(eval $(call BuildPlugin,iptables-mod-weburl,$(IPT_WEBURL-m)))
$(eval $(call BuildPlugin,iptables-mod-ipopt,$(IPT_IPOPT-m)))
$(eval $(call BuildPlugin,iptables-mod-ipsec,$(IPT_IPSEC-m)))
$(eval $(call BuildPlugin,iptables-mod-nat-extra,$(IPT_NAT_EXTRA-m)))