Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  mptcp_lib.sh   Sprache: Shell

 
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0

"$(dirname "${0}")/../lib.sh"

readonly KSFT_PASS=0
readonly KSFT_FAIL=1
readonly KSFT_SKIP=4

# shellcheck disable=SC2155 # declare and assign separately
readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}"

# These variables are used in some selftests, read-only
declare -rx MPTCP_LIB_EVENT_CREATED=1           # MPTCP_EVENT_CREATED
declare -rx MPTCP_LIB_EVENT_ESTABLISHED=2       # MPTCP_EVENT_ESTABLISHED
declare -rx MPTCP_LIB_EVENT_CLOSED=3            # MPTCP_EVENT_CLOSED
declare -rx MPTCP_LIB_EVENT_ANNOUNCED=6         # MPTCP_EVENT_ANNOUNCED
declare -rx MPTCP_LIB_EVENT_REMOVED=7           # MPTCP_EVENT_REMOVED
declare -rx MPTCP_LIB_EVENT_SUB_ESTABLISHED=10  # MPTCP_EVENT_SUB_ESTABLISHED
declare -rx MPTCP_LIB_EVENT_SUB_CLOSED=11       # MPTCP_EVENT_SUB_CLOSED
declare -rx MPTCP_LIB_EVENT_SUB_PRIORITY=13     # MPTCP_EVENT_SUB_PRIORITY
declare -rx MPTCP_LIB_EVENT_LISTENER_CREATED=15 # MPTCP_EVENT_LISTENER_CREATED
declare -rx MPTCP_LIB_EVENT_LISTENER_CLOSED=16  # MPTCP_EVENT_LISTENER_CLOSED

declare -rx MPTCP_LIB_AF_INET=2
declare -rx MPTCP_LIB_AF_INET6=10

MPTCP_LIB_SUBTESTS=()
MPTCP_LIB_SUBTESTS_DUPLICATED=0
MPTCP_LIB_SUBTEST_FLAKY=0
MPTCP_LIB_SUBTESTS_LAST_TS_MS=
MPTCP_LIB_TEST_COUNTER=0
MPTCP_LIB_TEST_FORMAT="%02u %-50s"
MPTCP_LIB_IP_MPTCP=0

# only if supported (or forced) and not disabled, see no-color.org
if { [ -t 1 ] || [ "${SELFTESTS_MPTCP_LIB_COLOR_FORCE:-}" = "1" ]; } &&
   [ "${NO_COLOR:-}" != "1" ]; then
 readonly MPTCP_LIB_COLOR_RED="\E[1;31m"
 readonly MPTCP_LIB_COLOR_GREEN="\E[1;32m"
 readonly MPTCP_LIB_COLOR_YELLOW="\E[1;33m"
 readonly MPTCP_LIB_COLOR_BLUE="\E[1;34m"
 readonly MPTCP_LIB_COLOR_RESET="\E[0m"
else
 readonly MPTCP_LIB_COLOR_RED=
 readonly MPTCP_LIB_COLOR_GREEN=
 readonly MPTCP_LIB_COLOR_YELLOW=
 readonly MPTCP_LIB_COLOR_BLUE=
 readonly MPTCP_LIB_COLOR_RESET=
fi

# SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY env var can be set not to ignore errors
# from subtests marked as flaky
mptcp_lib_override_flaky() {
 [ "${SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY:-}" = 1 ]
}

mptcp_lib_subtest_is_flaky() {
 [ "${MPTCP_LIB_SUBTEST_FLAKY}" = 1 ] && ! mptcp_lib_override_flaky
}

# $1: color, $2: text
mptcp_lib_print_color() {
 echo -e "${MPTCP_LIB_START_PRINT:-}${*}${MPTCP_LIB_COLOR_RESET}"
}

mptcp_lib_print_ok() {
 mptcp_lib_print_color "${MPTCP_LIB_COLOR_GREEN}${*}"
}

mptcp_lib_print_warn() {
 mptcp_lib_print_color "${MPTCP_LIB_COLOR_YELLOW}${*}"
}

mptcp_lib_print_info() {
 mptcp_lib_print_color "${MPTCP_LIB_COLOR_BLUE}${*}"
}

mptcp_lib_print_err() {
 mptcp_lib_print_color "${MPTCP_LIB_COLOR_RED}${*}"
}

# shellcheck disable=SC2120 # parameters are optional
mptcp_lib_pr_ok() {
 mptcp_lib_print_ok "[ OK ]${1:+ ${*}}"
}

mptcp_lib_pr_skip() {
 mptcp_lib_print_warn "[SKIP]${1:+ ${*}}"
}

mptcp_lib_pr_fail() {
 local title cmt

 if mptcp_lib_subtest_is_flaky; then
  title="IGNO"
  cmt=" (flaky)"
 else
  title="FAIL"
 fi

 mptcp_lib_print_err "[${title}]${cmt}${1:+ ${*}}"
}

mptcp_lib_pr_info() {
 mptcp_lib_print_info "INFO: ${*}"
}

# $1-2: listener/connector ns ; $3 port ; $4-5 listener/connector stat file
mptcp_lib_pr_err_stats() {
 local lns="${1}"
 local cns="${2}"
 local port="${3}"
 local lstat="${4}"
 local cstat="${5}"

 echo -en "${MPTCP_LIB_COLOR_RED}"
 {
  printf "\nnetns %s (listener) socket stat for %d:\n" "${lns}" "${port}"
  ip netns exec "${lns}" ss -Menitam -o "sport = :${port}"
  cat "${lstat}"

  printf "\nnetns %s (connector) socket stat for %d:\n" "${cns}" "${port}"
  ip netns exec "${cns}" ss -Menitam -o "dport = :${port}"
  [ "${lstat}" != "${cstat}" ] && cat "${cstat}"
 } 1>&2
 echo -en "${MPTCP_LIB_COLOR_RESET}"
}

# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
# features using the last version of the kernel and the selftests to make sure
# a test is not being skipped by mistake.
mptcp_lib_expect_all_features() {
 [ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
}

# $1: msg
mptcp_lib_fail_if_expected_feature() {
 if mptcp_lib_expect_all_features; then
  echo "ERROR: missing feature: ${*}"
  exit ${KSFT_FAIL}
 fi

 return 1
}

# $1: file
mptcp_lib_has_file() {
 local f="${1}"

 if [ -f "${f}" ]; then
  return 0
 fi

 mptcp_lib_fail_if_expected_feature "${f} file not found"
}

mptcp_lib_check_mptcp() {
 if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"then
  mptcp_lib_pr_skip "MPTCP support is not available"
  exit ${KSFT_SKIP}
 fi
}

mptcp_lib_check_kallsyms() {
 if ! mptcp_lib_has_file "/proc/kallsyms"then
  mptcp_lib_pr_skip "CONFIG_KALLSYMS is missing"
  exit ${KSFT_SKIP}
 fi
}

# Internal: use mptcp_lib_kallsyms_has() instead
__mptcp_lib_kallsyms_has() {
 local sym="${1}"

 mptcp_lib_check_kallsyms

 grep -q " ${sym}" /proc/kallsyms
}

# $1: part of a symbol to look at, add '$' at the end for full name
mptcp_lib_kallsyms_has() {
 local sym="${1}"

 if __mptcp_lib_kallsyms_has "${sym}"then
  return 0
 fi

 mptcp_lib_fail_if_expected_feature "${sym} symbol not found"
}

# $1: part of a symbol to look at, add '$' at the end for full name
mptcp_lib_kallsyms_doesnt_have() {
 local sym="${1}"

 if ! __mptcp_lib_kallsyms_has "${sym}"then
  return 0
 fi

 mptcp_lib_fail_if_expected_feature "${sym} symbol has been found"
}

# !!!AVOID USING THIS!!!
# Features might not land in the expected version and features can be backported
#
# $1: kernel version, e.g. 6.3
mptcp_lib_kversion_ge() {
 local exp_maj="${1%.*}"
 local exp_min="${1#*.}"
 local v maj min

 # If the kernel has backported features, set this env var to 1:
 if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
  return 0
 fi

 v=$(uname -r | cut -d'.' -f1,2)
 maj=${v%.*}
 min=${v#*.}

 if   [ "${maj}" -gt "${exp_maj}" ] ||
    { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
  return 0
 fi

 mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}"
}

mptcp_lib_subtests_last_ts_reset() {
 MPTCP_LIB_SUBTESTS_LAST_TS_MS="$(date +%s%3N)"
}
mptcp_lib_subtests_last_ts_reset

__mptcp_lib_result_check_duplicated() {
 local subtest

 for subtest in "${MPTCP_LIB_SUBTESTS[@]}"do
  if [[ "${subtest}" == *" - ${KSFT_TEST}: ${*%% #*}" ]]; then
   MPTCP_LIB_SUBTESTS_DUPLICATED=1
   mptcp_lib_print_err "Duplicated entry: ${*}"
   break
  fi
 done
}

__mptcp_lib_result_add() {
 local result="${1}"
 local time="time="
 local ts_prev_ms
 shift

 local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1))

 __mptcp_lib_result_check_duplicated "${*}"

 # not to add two '#'
 [[ "${*}" != *"#"* ]] && time="# ${time}"

 ts_prev_ms="${MPTCP_LIB_SUBTESTS_LAST_TS_MS}"
 mptcp_lib_subtests_last_ts_reset
 time+="$((MPTCP_LIB_SUBTESTS_LAST_TS_MS - ts_prev_ms))ms"

 MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*} ${time}")
}

# $1: test name
mptcp_lib_result_pass() {
 __mptcp_lib_result_add "ok" "${1}"
}

# $1: test name
mptcp_lib_result_fail() {
 if mptcp_lib_subtest_is_flaky; then
  # It might sound better to use 'not ok # TODO' or 'ok # SKIP',
  # but some CIs don't understand 'TODO' and treat SKIP as errors.
  __mptcp_lib_result_add "ok" "${1} # IGNORE Flaky"
 else
  __mptcp_lib_result_add "not ok" "${1}"
 fi
}

# $1: test name
mptcp_lib_result_skip() {
 __mptcp_lib_result_add "ok" "${1} # SKIP"
}

# $1: result code ; $2: test name
mptcp_lib_result_code() {
 local ret="${1}"
 local name="${2}"

 case "${ret}" in
  "${KSFT_PASS}")
   mptcp_lib_result_pass "${name}"
   ;;
  "${KSFT_FAIL}")
   mptcp_lib_result_fail "${name}"
   ;;
  "${KSFT_SKIP}")
   mptcp_lib_result_skip "${name}"
   ;;
  *)
   echo "ERROR: wrong result code: ${ret}"
   exit ${KSFT_FAIL}
   ;;
 esac
}

mptcp_lib_result_print_all_tap() {
 local subtest

 if [ ${#MPTCP_LIB_SUBTESTS[@]} -eq 0 ] ||
    [ "${SELFTESTS_MPTCP_LIB_NO_TAP:-}" = "1" ]; then
  return
 fi

 printf "\nTAP version 13\n"
 printf "1..%d\n" "${#MPTCP_LIB_SUBTESTS[@]}"

 for subtest in "${MPTCP_LIB_SUBTESTS[@]}"do
  printf "%s\n" "${subtest}"
 done

 if [ "${MPTCP_LIB_SUBTESTS_DUPLICATED}" = 1 ] &&
    mptcp_lib_expect_all_features; then
  mptcp_lib_print_err "Duplicated test entries"
  exit ${KSFT_FAIL}
 fi
}

# get the value of keyword $1 in the line marked by keyword $2
mptcp_lib_get_info_value() {
 grep "${2}" 2>/dev/null |
  sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q'
  # the ';q' at the end limits to the first matched entry.
}

# $1: info name ; $2: evts_ns ; [$3: event type; [$4: addr]]
mptcp_lib_evts_get_info() {
 grep "${4:-}" "${2}" 2>/dev/null |
  mptcp_lib_get_info_value "${1}" "^type:${3:-1},"
}

# $1: PID
mptcp_lib_kill_wait() {
 [ "${1}" -eq 0 ] && return 0

 kill -SIGUSR1 "${1}" > /dev/null 2>&1
 kill "${1}" > /dev/null 2>&1
 wait "${1}" 2>/dev/null
}

# $1: PID
mptcp_lib_pid_list_children() {
 local curr="${1}"
 # evoke 'ps' only once
 local pids="${2:-"$(ps o pid,ppid)"}"

 echo "${curr}"

 local pid
 for pid in $(echo "${pids}" | awk "\$2 == ${curr} { print \$1 }"); do
  mptcp_lib_pid_list_children "${pid}" "${pids}"
 done
}

# $1: PID
mptcp_lib_kill_group_wait() {
 # Some users might not have procps-ng: cannot use "kill -- -PID"
 mptcp_lib_pid_list_children "${1}" | xargs -r kill &>/dev/null
 wait "${1}" 2>/dev/null
}

# $1: IP address
mptcp_lib_is_v6() {
 [ -z "${1##*:*}" ]
}

# $1: ns, $2: MIB counter
mptcp_lib_get_counter() {
 local ns="${1}"
 local counter="${2}"
 local count

 count=$(ip netns exec "${ns}" nstat -asz "${counter}" |
  awk 'NR==1 {next} {print $2}')
 if [ -z "${count}" ]; then
  mptcp_lib_fail_if_expected_feature "${counter} counter"
  return 1
 fi

 echo "${count}"
}

mptcp_lib_make_file() {
 local name="${1}"
 local bs="${2}"
 local size="${3}"

 dd if=/dev/urandom of="${name}" bs="${bs}" count="${size}" 2> /dev/null
 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "${name}"
}

# $1: file
mptcp_lib_print_file_err() {
 ls -l "${1}" 1>&2
 echo "Trailing bytes are: "
 tail -c 32 "${1}" | od -x | head -n2
}

# $1: input file ; $2: output file ; $3: what kind of file
mptcp_lib_check_transfer() {
 local in="${1}"
 local out="${2}"
 local what="${3}"

 if ! cmp "$in" "$out" > /dev/null 2>&1; then
  mptcp_lib_pr_fail "$what does not match (in, out):"
  mptcp_lib_print_file_err "$in"
  mptcp_lib_print_file_err "$out"

  return 1
 fi

 return 0
}

# $1: ns, $2: port
mptcp_lib_wait_local_port_listen() {
 wait_local_port_listen "${@}" "tcp"
}

mptcp_lib_check_output() {
 local err="${1}"
 local cmd="${2}"
 local expected="${3}"
 local cmd_ret=0
 local out

 if ! out=$(${cmd} 2>"${err}"); then
  cmd_ret=${?}
 fi

 if [ ${cmd_ret} -ne 0 ]; then
  mptcp_lib_pr_fail "command execution '${cmd}' stderr"
  cat "${err}"
  return 2
 elif [ "${out}" = "${expected}" ]; then
  return 0
 else
  mptcp_lib_pr_fail "expected '${expected}' got '${out}'"
  return 1
 fi
}

mptcp_lib_check_tools() {
 local tool

 for tool in "${@}"do
  case "${tool}" in
  "ip")
   if ! ip -Version &> /dev/null; then
    mptcp_lib_pr_skip "Could not run test without ip tool"
    exit ${KSFT_SKIP}
   fi
   ;;
  "tc")
   if ! tc -help &> /dev/null; then
    mptcp_lib_pr_skip "Could not run test without tc tool"
    exit ${KSFT_SKIP}
   fi
   ;;
  "ss")
   if ! ss -h | grep -q MPTCP; then
    mptcp_lib_pr_skip "ss tool does not support MPTCP"
    exit ${KSFT_SKIP}
   fi
   ;;
  "iptables"* | "ip6tables"*)
   if ! "${tool}" -V &> /dev/null; then
    mptcp_lib_pr_skip "Could not run all tests without ${tool}"
    exit ${KSFT_SKIP}
   fi
   ;;
  *)
   mptcp_lib_pr_fail "Internal error: unsupported tool: ${tool}"
   exit ${KSFT_FAIL}
   ;;
  esac
 done
}

mptcp_lib_ns_init() {
 if ! setup_ns "${@}"then
  mptcp_lib_pr_fail "Failed to setup namespaces ${*}"
  exit ${KSFT_FAIL}
 fi

 local netns
 for netns in "${@}"do
  ip netns exec "${!netns}" sysctl -q net.mptcp.enabled=1
 done
}

mptcp_lib_ns_exit() {
 cleanup_ns "${@}"

 local netns
 for netns in "${@}"do
  rm -f /tmp/"${netns}".{nstat,out}
 done
}

mptcp_lib_events() {
 local ns="${1}"
 local evts="${2}"
 declare -n pid="${3}"

 :>"${evts}"

 mptcp_lib_kill_wait "${pid:-0}"
 ip netns exec "${ns}" ./pm_nl_ctl events >> "${evts}" 2>&1 &
 pid=$!
}

mptcp_lib_print_title() {
 : "${MPTCP_LIB_TEST_COUNTER:?}"
 : "${MPTCP_LIB_TEST_FORMAT:?}"

 # shellcheck disable=SC2059 # the format is in a variable
 printf "${MPTCP_LIB_TEST_FORMAT}" "$((++MPTCP_LIB_TEST_COUNTER))" "${*}"
}

# $1: var name ; $2: prev ret
mptcp_lib_check_expected_one() {
 local var="${1}"
 local exp="e_${var}"
 local prev_ret="${2}"

 if [ "${!var}" = "${!exp}" ]; then
  return 0
 fi

 if [ "${prev_ret}" = "0" ]; then
  mptcp_lib_pr_fail
 fi

 mptcp_lib_print_err "Expected value for '${var}': '${!exp}', got '${!var}'."
 return 1
}

# $@: all var names to check
mptcp_lib_check_expected() {
 local rc=0
 local var

 for var in "${@}"do
  mptcp_lib_check_expected_one "${var}" "${rc}" || rc=1
 done

 return "${rc}"
}

# shellcheck disable=SC2034 # Some variables are used below but indirectly
mptcp_lib_verify_listener_events() {
 local evt=${1}
 local e_type=${2}
 local e_family=${3}
 local e_saddr=${4}
 local e_sport=${5}
 local type
 local family
 local saddr
 local sport
 local rc=0

 type=$(mptcp_lib_evts_get_info type "${evt}" "${e_type}")
 family=$(mptcp_lib_evts_get_info family "${evt}" "${e_type}")
 if [ "${family}" ] && [ "${family}" = "${AF_INET6}" ]; then
  saddr=$(mptcp_lib_evts_get_info saddr6 "${evt}" "${e_type}")
 else
  saddr=$(mptcp_lib_evts_get_info saddr4 "${evt}" "${e_type}")
 fi
 sport=$(mptcp_lib_evts_get_info sport "${evt}" "${e_type}")

 mptcp_lib_check_expected "type" "family" "saddr" "sport" || rc="${?}"
 return "${rc}"
}

mptcp_lib_set_ip_mptcp() {
 MPTCP_LIB_IP_MPTCP=1
}

mptcp_lib_is_ip_mptcp() {
 [ "${MPTCP_LIB_IP_MPTCP}" = "1" ]
}

# format: <id>,<ip>,<flags>,<dev>
mptcp_lib_pm_nl_format_endpoints() {
 local entry id ip flags dev port

 for entry in "${@}"do
  IFS=, read -r id ip flags dev port <<< "${entry}"
  if mptcp_lib_is_ip_mptcp; then
   echo -n "${ip}"
   [ -n "${port}" ] && echo -n " port ${port}"
   echo -n " id ${id}"
   [ -n "${flags}" ] && echo -n " ${flags}"
   [ -n "${dev}" ] && echo -n " dev ${dev}"
   echo " " # always a space at the end
  else
   echo -n "id ${id}"
   echo -n " flags ${flags//" "/","}"
   [ -n "${dev}" ] && echo -n " dev ${dev}"
   echo -n " ${ip}"
   [ -n "${port}" ] && echo -n " ${port}"
   echo ""
  fi
 done
}

mptcp_lib_pm_nl_get_endpoint() {
 local ns=${1}
 local id=${2}

 if mptcp_lib_is_ip_mptcp; then
  ip -n "${ns}" mptcp endpoint show id "${id}"
 else
  ip netns exec "${ns}" ./pm_nl_ctl get "${id}"
 fi
}

mptcp_lib_pm_nl_set_limits() {
 local ns=${1}
 local addrs=${2}
 local subflows=${3}

 if mptcp_lib_is_ip_mptcp; then
  ip -n "${ns}" mptcp limits set add_addr_accepted "${addrs}" subflows "${subflows}"
 else
  ip netns exec "${ns}" ./pm_nl_ctl limits "${addrs}" "${subflows}"
 fi
}

mptcp_lib_pm_nl_add_endpoint() {
 local ns=${1}
 local addr=${2}
 local flags dev id port
 local nr=2

 local p
 for p in "${@}"do
  case "${p}" in
  "flags" | "dev" | "id" | "port")
   eval "${p}"=\$"${nr}"
   ;;
  esac

  nr=$((nr + 1))
 done

 if mptcp_lib_is_ip_mptcp; then
  # shellcheck disable=SC2086 # blanks in flags, no double quote
  ip -n "${ns}" mptcp endpoint add "${addr}" ${flags//","/" "} \
   ${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"}
 else
  ip netns exec "${ns}" ./pm_nl_ctl add "${addr}" ${flags:+flags "${flags}"} \
   ${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"}
 fi
}

mptcp_lib_pm_nl_del_endpoint() {
 local ns=${1}
 local id=${2}
 local addr=${3}

 if mptcp_lib_is_ip_mptcp; then
  [ "${id}" -ne 0 ] && addr=''
  ip -n "${ns}" mptcp endpoint delete id "${id}" ${addr:+"${addr}"}
 else
  ip netns exec "${ns}" ./pm_nl_ctl del "${id}" "${addr}"
 fi
}

mptcp_lib_pm_nl_flush_endpoint() {
 local ns=${1}

 if mptcp_lib_is_ip_mptcp; then
  ip -n "${ns}" mptcp endpoint flush
 else
  ip netns exec "${ns}" ./pm_nl_ctl flush
 fi
}

mptcp_lib_pm_nl_show_endpoints() {
 local ns=${1}

 if mptcp_lib_is_ip_mptcp; then
  ip -n "${ns}" mptcp endpoint show
 else
  ip netns exec "${ns}" ./pm_nl_ctl dump
 fi
}

mptcp_lib_pm_nl_change_endpoint() {
 local ns=${1}
 local id=${2}
 local flags=${3}

 if mptcp_lib_is_ip_mptcp; then
  # shellcheck disable=SC2086 # blanks in flags, no double quote
  ip -n "${ns}" mptcp endpoint change id "${id}" ${flags//","/" "}
 else
  ip netns exec "${ns}" ./pm_nl_ctl set id "${id}" flags "${flags}"
 fi
}

Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge