1 ## @defgroup services Dienste
2 ## @brief Verwaltung von Diensten (z.B. via olsrd-nameservice announciert)
3 # Beginn der Doku-Gruppe
6 VOLATILE_SERVICE_STATUS_DIR=/tmp/on-services-
volatile.d
7 PERSISTENT_SERVICE_STATUS_DIR=/etc/on-services.d
8 # eine grosse Zahl sorgt dafuer, dass neu entdeckte Dienste hinten angehaengt werden
9 DEFAULT_SERVICE_RANK=10000
10 DEFAULT_SERVICE_SORTING=etx
11 # Die folgenden Attribute werden dauerhaft (im Flash) gespeichert. Häufige Änderungen sind also eher unerwünscht.
12 # Gruende fuer ausgefallene/unintuitive Attribute:
13 # uci_dependency: später zu beräumende uci-Einträge wollen wir uns merken
14 # file_dependency: siehe uci_dependency
15 # priority: DNS-entdeckte Dienste enthalten ein "priority"-Attribut, nach einem reboot wieder verfügbar sein sollte
16 # rank/offset: Attribute zur Ermittlung der Dienstreihenfolge
17 # disabled: der Dienst wurde vom Nutzenden an- oder abgewählt
18 # local_relay_port: der lokale Port, der für eine Dienst-Weiterleitung verwendet wird - er sollte über reboots hinweg stabil sein
19 # source: die Quelle des Diensts (olsrd/dns/manual) muss erhalten bleiben, um ihn später löschen zu können
20 PERSISTENT_SERVICE_ATTRIBUTES=
"service scheme host port protocol path uci_dependency file_dependency priority rank offset disabled source local_relay_port"
22 SERVICES_LOG_BASE=/var/log/on-services
25 ## @fn get_service_name()
26 ## @brief Ermittle en Namen eines Diensts basierend auf den Dienst-Attributen.
27 ## @details Reihenfolge der Eingabeparameter: SERVICE_TYPE SCHEMA HOST PORT PROTOCOL PATH
35 local name=
"${service}_${scheme}_${host}_${port}_${protocol}"
36 [ -n
"${path#/}" ] && name=
"${name}_${path#/}"
37 echo
"$name" | sed
's/[^A-Za-z0-9_]/_/g'
41 ## @fn notify_service()
42 ## @brief Aktualisiere den Zeitstempel und die Entfernung (etx) eines Dienstes
43 ## @returns Der Dienstname wird ausgegeben.
45 trap
"error_trap notify_service '$*'" $GUARD_TRAPS
55 service_name=$(
get_service_name "$service" "$scheme" "$host" "$port" "$protocol" "$path")
57 # diese Attribute sind Bestandteil des Namens und aendern sich eigentlich nicht
58 set_service_value
"$service_name" "service" "$service"
59 set_service_value
"$service_name" "scheme" "$scheme"
60 set_service_value
"$service_name" "host" "$host"
61 set_service_value
"$service_name" "port" "$port"
62 set_service_value
"$service_name" "protocol" "$protocol"
63 set_service_value
"$service_name" "path" "$path"
65 # dies sind die flexiblen Attribute
66 set_service_value
"$service_name" "details" "$details"
67 set_service_value
"$service_name" "timestamp" "$(get_uptime_minutes)"
68 set_service_value
"$service_name" "source" "$source"
74 ## @fn update_service_routing_distance()
75 ## @brief Aktualisiere Routing-Entfernung und Hop-Count eines Dienst-Anbieters
76 ## @param service_name der zu aktualisierende Dienst
77 ## @details Beide Dienst-Werte werden gelöscht, falls der Host nicht route-bar sein sollte.
78 ## Diese Funktion sollte regelmäßig für alle Hosts ausgeführt werden.
80 trap
"error_trap update_service_routing_distance '$*'" $GUARD_TRAPS
81 local service_name=
"$1"
85 set_service_value
"$service_name" "distance" "$etx"
86 set_service_value
"$service_name" "hop_count" "$hop"
91 ## @fn is_existing_service()
92 ## @brief Prüfe ob ein Service existiert
93 ## @param service_name der Name des Diensts
94 ## @returns exitcode=0 falls der Dienst existiert
96 local service_name=
"$1"
97 [ -n
"$service_name" -a -e
"$PERSISTENT_SERVICE_STATUS_DIR/$service_name" ] &&
return 0
98 trap
"" $GUARD_TRAPS &&
return 1
102 ## @fn _get_local_bias_for_service()
103 ## @brief Ermittle eine reproduzierbare Zahl von 0 bis (LOCAL_BIAS_MODULO-1) - abhängig von der lokalen IP und dem Dienstnamen.
104 ## @param service_name der Name des Diensts für den ein Bias-Wert zu ermitteln ist.
105 ## @details Dadurch können wir beim Sortieren strukturelle Bevorzugungen (z.B. durch alphabetische Sortierung) verhindern.
107 local service_name=
"$1"
108 # lade den Wert aus dem Cache, falls moeglich
111 if [ -z
"$bias_cache" ]; then
112 # Die resultierende host_number darf nicht zu gross sein (z.B. mit Exponentendarstellung),
113 # da andernfalls awk die Berechnung fehlerhaft durchführt.
115 host_number=$(echo
"$service_name$(get_local_bias_number)" | md5sum | sed
's/[^0-9]//g')
116 # Laenge von
'host_number' reduzieren (die Berechnung schlaegt sonst fehl)
117 # Wir fuegen die 1 an den Beginn, um die Interpretation als octal-Zahl zu verhindern (fuehrende Null).
118 bias_cache=$(( 1${host_number:0:6} % LOCAL_BIAS_MODULO))
119 set_service_value
"$service_name" "local_bias" "$bias_cache"
121 echo -n
"$bias_cache"
125 # Ermittle die Service-Prioritaet eines Dienstes.
126 # Der Wert ist beliebig und nur im Vergleich mit den Prioritaeten der anderen Dienste verwendbar.
127 # Als optionaler zweiter Parameter kann die Sortierung uebergeben werden. Falls diese nicht uebergeben wurde,
128 # wird die aktuell konfigurierte Sortierung benutzt.
129 # Sollte ein Dienst ein "priority"-Attribut tragen, dann wird die uebliche Dienst-Sortierung aufgehoben
130 # und lediglich "priority" (und gegebenenfalls separat "offset") beachtet.
131 get_service_priority() {
132 trap
"error_trap get_service_priority '$*'" $GUARD_TRAPS
133 local service_name=
"$1"
134 local sorting=
"${2:-}"
138 # priority wird von nicht-olsr-Clients verwendet (z.B. mesh-Gateways mit oeffentlichen IPs)
141 if [ -n
"$priority" ]; then
142 # dieses Ziel traegt anscheinend keine Routing-Metrik
145 echo
"$((priority + offset))"
147 # wir benoetigen Informationen fuer Ziele mit Routing-Metriken
148 # aus Performance-Gruenden kommt die Sortierung manchmal von aussen
149 [ -z
"$sorting" ] && sorting=$(get_service_sorting)
150 if [
"$sorting" =
"etx" -o
"$sorting" =
"hop" ]; then
151 get_distance_with_offset
"$service_name" "$sorting"
152 elif [
"$sorting" =
"manual" ]; then
155 msg_error "Unknown sorting method for services: $sorting"
161 echo
"${base_priority:-$DEFAULT_SERVICE_RANK}" | awk
'{ print $1 * 1000 + '$service_bias
'; }'
165 get_distance_with_offset() {
166 trap
"error_trap get_distance_with_offset '$*'" $GUARD_TRAPS
167 local service_name=
"$1"
168 local sorting=
"${2:-}"
172 # aus Performance-Gruenden wird manchmal das sorting von aussen vorgegeben
173 [ -z
"$sorting" ] && sorting=$(get_service_sorting)
175 [ -z
"$distance" ] &&
return 0
177 [ -z
"$offset" ] && offset=0
178 if [
"$sorting" =
"etx" ]; then
179 base_value=
"$distance"
180 elif [
"$sorting" =
"hop" ]; then
183 msg_debug "get_distance_with_offset: sorting '$sorting' not implemented"
185 [ -n
"$base_value" ] && echo
"$base_value" "$offset" | awk
'{ print $1 + $2 }'
190 set_service_sorting() {
191 trap
"error_trap set_service_sorting '$*'" $GUARD_TRAPS
192 local new_sorting=
"$1"
194 old_sorting=$(get_service_sorting)
195 [
"$old_sorting" =
"$new_sorting" ] &&
return 0
196 [
"$new_sorting" !=
"manual" -a
"$new_sorting" !=
"hop" -a
"$new_sorting" !=
"etx" ] && \
197 msg_error "Ignoring unknown sorting method: $new_sorting" && \
198 trap
"" $GUARD_TRAPS &&
return 1
199 uci set
"on-core.settings.service_sorting=$new_sorting"
200 apply_changes on-core
204 # Liefere die aktuelle Sortier-Methode.
205 # Falls eine ungueltige Sortier-Methode gesetzt ist, wird diese auf die Standard-Sortierung zurueckgesetzt.
206 # Die Ausgabe dieser Funktion ist also in jedem Fall eine gueltige Sortier-Methode.
207 get_service_sorting() {
208 trap
"error_trap get_service_sorting '$*'" $GUARD_TRAPS
210 sorting=$(uci_get
"on-core.settings.service_sorting")
211 if [
"$sorting" =
"manual" -o
"$sorting" =
"hop" -o
"$sorting" =
"etx" ]; then
212 # zulaessige Sortierung
215 # unbekannte Sortierung: dauerhaft setzen
216 # keine Warnung falls die Sortierung nicht gesetzt wurde
217 [ -n
"$sorting" ] &&
msg_error "coercing unknown sorting method: $sorting -> $DEFAULT_SERVICE_SORTING"
218 uci set
"on-core.settings.service_sorting=$DEFAULT_SERVICE_SORTING"
219 echo -n
"$DEFAULT_SERVICE_SORTING"
225 ## @fn sort_services_by_priority()
226 ## @brief Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste.
227 ## @details Die Prioritätsinformation wird typischerweise für nicht-mesh-verteilte Dienste verwendet (z.B. den mesh-Tunnel).
229 trap
"error_trap sort_services_by_priority '$*'" $GUARD_TRAPS
233 sorting=$(get_service_sorting)
234 while read service_name;
do
235 priority=$(get_service_priority
"$service_name" "$sorting")
236 # keine Entfernung (nicht erreichbar) -> ganz nach hinten sortieren (schmutzig, aber wohl ausreichend)
237 [ -z
"$priority" ] && priority=999999999999999
238 echo
"$priority" "$service_name"
239 done | sort -n | awk
'{print $2}'
243 ## @fn filter_reachable_services()
244 ## @brief Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die erreichbar sind.
245 ## @details Die Dienst-Namen werden über die Standardeingabe gelesen und an die Standardausgabe
246 ## weitergeleitet, falls der Dienst erreichbar sind. "Erreichbarkeit" gilt als erreicht, wenn
247 ## der Host via olsr route-bar ist oder wenn er als DNS-entdeckter Dienst eine Priorität hat
248 ## oder wenn er manuell hinzugefügt wurde.
251 while read service_name;
do
252 { [ -n
"$(get_service_value "$service_name
" "distance
")" ] \
253 || [ -n
"$(get_service_value "$service_name
" "priority
")" ] \
254 || [
"$(get_service_value "$service_name
" "source
")" =
"manual" ]
255 } && echo
"$service_name"
261 ## @fn filter_enabled_services()
262 ## @brief Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die nicht manuell ausgeblendet wurden.
263 ## @details Die Dienst-Namen werden über die Standardeingabe gelesen und an
264 ## die Standardausgabe weitergeleitet, falls der Dienst nicht abgewählt wurde.
268 while read service_name;
do
270 [ -n
"$disabled" ] && uci_is_true
"$disabled" &&
continue
277 ## @brief Liefere zu einer Reihe von Diensten ein gewähltes Attribut dieser Dienste zurück.
278 ## @param key Der Name eines Dienst-Attributs
279 ## @param default Der Standard-Wert wird anstelle des Attribut-Werts verwendet, falls dieser leer ist.
280 ## @details Die Dienstenamen werden via Standardeingabe erwartet. Auf der Standardausgabe wird für
281 ## einen Dienst entweder ein Wert oder nichts ausgeliefert. Keine Ausgabe erfolgt, falls der
282 ## Wert des Dienste-Attributs leer ist. Bei der Eingabe von mehreren Diensten werden also
283 ## eventuell weniger Zeilen ausgegeben, als eingelesen wurden.
284 ## Falls der optionale zweite 'default'-Parameter nicht leer ist, dann wird bei einem leeren
285 ## Ergebnis stattdessen dieser Wert ausgegeben. Der 'default'-Parameter sorgt somit dafür, dass
286 ## die Anzahl der eingelesenen Zeilen in jedem Fall mit der Anzahl der ausgegebenen Zeilen
290 local
default=
"${2:-}"
293 while read service_name;
do
295 [ -z
"$value" ] &&
value=
"$default"
296 [ -n
"$value" ] && echo
"$value" ||
true
302 ## @param service_type (optional) ein Service-Typ
303 ## @brief Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind.
304 ## Falls kein Typ angegben wird, dann werden alle Dienste ungeachtet ihres Typs ausgegeben.
306 trap
"error_trap get_services '$*'" $GUARD_TRAPS
307 local service_type=
"${1:-}"
310 # alle Dienste ausgeben
311 # kein Dienste-Verzeichnis? Keine Ergebnisse ...
312 [ -e
"$PERSISTENT_SERVICE_STATUS_DIR" ] ||
return 0
313 find
"$PERSISTENT_SERVICE_STATUS_DIR" -type f -size +1c -print0 \
314 | xargs -0 -r -n 1 basename \
315 |
if [ -n
"$service_type" ]; then
323 ## @fn filter_services_by_value()
324 ## @param key ein Schlüssel
325 ## @param value ein Wert
326 ## @details Als Parameter kann ein "key/value"-Schluesselpaar angegeben werden.
327 ## Nur diejenigen Dienste, auf die diese Bedingung zutrifft, werden zurueckgeliefert.
332 while read service_name;
do
333 [
"$value" !=
"$(get_service_value "$service_name
" "$key
")" ] || echo
"$service_name"
338 # Setzen eines Werts fuer einen Dienst.
339 # Je nach Schluesselname wird der Inhalt in die persistente uci- oder
340 # die volatile tmpfs-Datenbank geschrieben.
341 set_service_value() {
342 local service_name=
"$1"
345 # unverändert? Schnell beenden
346 [ -n
"$service_name" -a
"$value" =
"$(get_service_value "$service_name
" "$attribute
")" ] &&
return 0
347 [ -z
"$service_name" ] \
348 &&
msg_error "No service given for attribute change ($attribute=$value)" \
349 && trap
"" $GUARD_TRAPS &&
return 1
351 if echo
"$PERSISTENT_SERVICE_ATTRIBUTES" | grep -q -w
"$attribute"; then
352 dirname=
"$PERSISTENT_SERVICE_STATUS_DIR"
354 dirname=
"$VOLATILE_SERVICE_STATUS_DIR"
356 _set_file_dict_value
"$dirname/$service_name" "$attribute" "$value"
360 ## @fn get_service_value()
361 ## @brief Auslesen eines Werts aus der Service-Datenbank.
362 ## @param key Der Name eines Dienst-Attributs
363 ## @param default Der Standard-Wert wird anstelle des Attribut-Werts verwendet, falls dieser leer ist.
364 ## @details Falls das Attribut nicht existiert, wird ein leerer Text zurückgeliefert.
365 ## Es gibt keinen abschließenden Zeilenumbruch.
367 local service_name=
"$1"
369 local
default=
"${3:-}"
372 [ -z
"$service_name" ] \
373 &&
msg_error "No service given for attribute request ('$attribute')" \
374 && trap
"" $GUARD_TRAPS &&
return 1
375 value=$(
_get_file_dict_value "$attribute" "$PERSISTENT_SERVICE_STATUS_DIR/$service_name" "$VOLATILE_SERVICE_STATUS_DIR/$service_name")
376 [ -n
"$value" ] && echo -n
"$value" || echo -n
"$default"
381 # Liefere die Suffixe aller Schluessel aus der Service-Attribut-Datenbank,
382 # die mit dem gegebenen Praefix uebereinstimmen.
383 get_service_attributes() {
384 _get_file_dict_keys
"$PERSISTENT_SERVICE_STATUS_DIR/$1" "$VOLATILE_SERVICE_STATUS_DIR/$1"
388 ## @fn print_services()
389 ## @brief menschenfreundliche Ausgabe der aktuell angemeldeten Dienste
390 ## @param service_type (optional) ein Service-Type
391 ## @returns Ausgabe der bekannten Dienste (für Menschen - nicht parsebar)
393 trap
"error_trap print_services '$*'" $GUARD_TRAPS
399 get_service_attributes
"$service_name" |
while read attribute;
do
401 echo -e
"\t$attribute=$value"
408 # Speichere das angegebene uci-Praefix als eine von einem Service abhaengige Konfiguration.
409 # Dies ist sinnvoll fuer abgeleitete VPN-Konfigurationen oder Portweiterleitungen.
410 # Schnittstelle: siehe _add_service_dependency
411 service_add_uci_dependency() {
412 _add_service_dependency
"uci_dependency" "$@"
416 # Speichere einen Dateinamen als Abhaengigkeit eines Service.
417 # Dies ist sinnvoll fuer Dateien, die nicht mehr gebraucht werden, sobald der Service entfernt wird.
418 # Schnittstelle: siehe _add_service_dependency
419 service_add_file_dependency() {
420 _add_service_dependency
"file_dependency" "$@"
424 # Speichere eine Abhaengigkeit fuer einen Dienst.
425 # Parameter: Service-Name
426 # Parameter: textuelle Darstellung einer Abhaengigkeit (ohne Leerzeichen)
427 _add_service_dependency() {
428 trap
"error_trap _add_service_dependency '$*'" $GUARD_TRAPS
429 local dependency=
"$1"
430 local service_name=
"$2"
436 # schon vorhanden -> fertig
437 [
"$dep" =
"$token" ] &&
return 0 ||
true
439 if [ -z
"$deps" ]; then
444 set_service_value
"$service_name" "$dependency" "$deps"
448 # Entferne alle mit diesem Service verbundenen Konfigurationen (inkl. Rekonfiguration von firewall, etc.).
449 cleanup_service_dependencies() {
450 trap
"error_trap cleanup_service_dependencies '$*'" $GUARD_TRAPS
451 local service_name=
"$1"
459 # uci-Sektionen loeschen
462 # gib die oberste config-Ebene aus - fuer spaeteres "apply_changes"
463 echo
"$dep" | cut -f 1 -
d .
464 done | sort | uniq |
while read branch;
do
465 apply_changes
"$branch"
467 set_service_value
"$service_name" "uci_dependency" ""
472 trap
"error_trap delete_service '$*'" $GUARD_TRAPS
473 local service_name=
"$1"
474 [ -z
"$service_name" ] &&
msg_error "No service given for deletion" && trap
"" $GUARD_TRAPS &&
return 1
475 cleanup_service_dependencies
"$service_name"
476 rm -f
"$PERSISTENT_SERVICE_STATUS_DIR/$service_name"
477 rm -f
"$VOLATILE_SERVICE_STATUS_DIR/$service_name"
481 # Durchlaufe alle Dienste und verteile Rangziffern ohne Doppelung an alle Dienste.
482 # Die Dienst-Arten (z.B. DNS und UGW) werden dabei nicht beachtet.
483 # Die Rangziffern sind anschliessend streng monoton aufsteigend - beginnend bei 1.
484 # Falls aktuell die manuelle Sortierung aktiv ist, wird deren Reihenfolge beibehalten.
485 # Ansonsten basiert die Vergabe der Rangziffern auf der Reihenfolge entsprechend der aktuell aktiven Sortierung.
486 _distribute_service_ranks() {
490 set_service_value
"$service_name" "rank" "$index"
496 ## @fn move_service_up()
497 ## @brief Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach oben
498 ## @param service_name der zu verschiebende Dienst
499 ## @param service_type der Service-Typ innerhalb derer Mitglieder die Verschiebung stattfinden soll
500 ## @details Für verschiedene Sortier-Modi hat dies verschiedene Auswirkungen:
501 ## * manual: Verschiebung vor den davorplatzierten Dienst desselben Typs
502 ## * etx/hop: Reduzierung des Offsets um eins
503 ## Falls keine Dienst-Typen angegeben sind, bewegt der Dienst sich in der globalen Liste nach unten.
505 trap
"error_trap move_service_up '$*'" $GUARD_TRAPS
506 local service_name=
"$1"
510 local current_service
512 sorting=$(get_service_sorting)
513 if [
"$sorting" =
"hop" -o
"$sorting" =
"etx" ]; then
514 # reduziere den Offset um eins
516 temp=$(echo
"$temp" | awk
'{ print $1 - 1 }')
517 set_service_value
"$service_name" "offset" "$temp"
518 elif [
"$sorting" =
"manual" ]; then
520 if [
"$current_service" =
"$service_name" ]; then
521 if [ -z
"$prev_service" ]; then
522 # es gibt keinen Dienst oberhalb des zu verschiebenden
525 # wir verschieben den Dienst ueber den davor liegenden
527 # ziehe einen halben Rang ab
528 temp=$(echo
"$temp" | awk
'{ print $1 - 0.5 }')
529 set_service_value
"$service_name" "rank" "$temp"
530 # erneuere die Rang-Vergabe
531 _distribute_service_ranks
536 prev_service=
"$current_service"
539 msg_info "Warning: [move_service_up] for this sorting method is not implemented: $sorting"
544 ## @fn move_service_down()
545 ## @brief Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach unten
546 ## @param service_name der zu verschiebende Dienst
547 ## @param service_type der Service-Typ innerhalb derer Mitglieder die Verschiebung stattfinden soll
548 ## @details Für verschiedene Sortier-Modi hat dies verschiedene Auswirkungen:
549 ## * manual: Verschiebung hinter den dahinterliegenden Dienst desselben Typs
550 ## * etx/hop: Erhöhung des Offsets um eins
551 ## Falls keine Dienst-Typen angegeben sind, bewegt der Dienst sich in der globalen Liste nach unten.
553 trap
"error_trap move_service_down '$*'" $GUARD_TRAPS
554 local service_name=
"$1"
558 local current_service
560 sorting=$(get_service_sorting)
561 if [
"$sorting" =
"hop" -o
"$sorting" =
"etx" ]; then
562 # reduziere den Offset um eins
564 temp=$(echo
"$temp" | awk
'{ print $1 + 1 }')
565 set_service_value
"$service_name" "offset" "$temp"
566 elif [
"$sorting" =
"manual" ]; then
568 if [
"$prev_service" =
"$service_name" ]; then
569 # wir verschieben den Dienst hinter den danach liegenden
571 # fuege einen halben Rang hinzu
572 temp=$(echo
"$temp" | awk
'{ print $1 + 0.5 }')
573 set_service_value
"$service_name" "rank" "$temp"
574 # erneuere die Rang-Vergabe
575 _distribute_service_ranks
579 prev_service=
"$current_service"
582 msg_info "Warning: [move_service_down] for this sorting method is not implemented: $sorting"
587 ## @fn move_service_top()
588 ## @brief Verschiebe einen Dienst an die Spitze der Dienst-Sortierung
589 ## @param service_name der zu verschiebende Dienst
590 ## @param service_types ein oder mehrere Dienst-Typen, auf die die Ermittlung der Dienst-Liste begrenzt werden soll (z.B. "gw")
591 ## @details Der Dienst steht anschließend direkt vor dem bisher führenden Dienst der ausgewählten Typen (falls angegeben).
592 ## Falls keine Dienst-Typen angegeben sind, bewegt der Dienst sich in der globalen Liste an die Spitze.
594 trap
"error_trap move_service_top '$*'" $GUARD_TRAPS
595 local service_name=
"$1"
606 sorting=$(get_service_sorting)
607 # kein top-Service oder wir sind bereits ganz oben -> Ende
608 [ -z
"$top_service" -o
"$top_service" =
"$service_name" ] &&
return 0
609 if [
"$sorting" =
"hop" -o
"$sorting" =
"etx" ]; then
610 top_distance=$(get_distance_with_offset
"$top_service" "$sorting")
611 our_distance=$(get_distance_with_offset
"$service_name" "$sorting")
612 [ -z
"$our_distance" ] &&
msg_info "Failed to move unreachable service ('$service_name') to top" &&
return 0
614 # wir verschieben unseren Offset, auf dass wir knapp ueber
"top" stehen
615 new_offset=$(echo | awk
"{ print $current_offset + int($top_distance - $our_distance) - 1 }")
616 set_service_value
"$service_name" "offset" "$new_offset"
617 elif [
"$sorting" =
"manual" ]; then
618 # setze den Rang des Dienstes auf den top-Dienst minus 0.5
620 new_rank=$(echo
"$top_rank" | awk
'{ print $1 - 0.5 }')
621 set_service_value
"$service_name" "rank" "$new_rank"
622 # erneuere die Rang-Vergabe
623 _distribute_service_ranks
625 msg_info "Warning: [move_service_top] for this sorting method is not implemented: $sorting"
630 ## @fn get_service_detail()
631 ## @brief Ermittle den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts
632 ## @param service_name Name eines Diensts
633 ## @param key Name des Schlüssels
634 ## @param default dieser Wert wird zurückgeliefert, falls der Schlüssel nicht gefunden wurde
635 ## @returns den ermittelten Wert aus dem Schlüssel-Wert-Paar
637 local service_name=
"$1"
639 local
default=
"${3:-}"
641 value=$(
get_service_value "$service_name" "details" | get_from_key_value_list
"$key" ":")
642 [ -n
"$value" ] && echo -n
"$value" || echo -n
"$default"
648 ## @brief Setze den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts
649 ## @param service_name Name eines Diensts
650 ## @param key Name des Schlüssels
651 ## @param value der neue Wert
652 ## @details Ein leerer Wert löscht das Schlüssel-Wert-Paar.
654 local service_name=
"$1"
658 new_details=$(
get_service_value "$service_name" "details" | replace_in_key_value_list
"$key" ":" "$value")
659 set_service_value
"$service_name" "details" "$new_details"
664 # Liefere eine Semikolon-separierte Liste von Service-Eigenschaften zurueck.
665 # Jede Eigenschaft wird folgendermassen ausgedrueckt:
666 # type|source|key[|
default]
667 # Dabei sind folgende Inhalte moeglich:
668 # type: Rueckgabetyp (
string, number,
bool)
669 # source: Quelle der Informationen (value, detail, function, id)
670 # key: Name des Werts, des Details oder der Funktion
671 # default: Standardwert, falls das Ergebnis leer sein sollte
672 # Wahrheitswerte werden als "true" oder "false" zurueckgeliefert. Alle anderen Rueckgabetypen bleiben unveraendert.
673 # Das Ergebnis sieht folgendermassen aus:
674 # SERVICE_NAME;RESULT1;RESULT2;...
675 get_service_as_csv() {
676 local service_name=
"$1"
686 # Abbruch mit Fehler bei unbekanntem Dienst
688 echo -n
"$service_name"
689 for specification in
"$@";
do
690 rtype=$(echo
"$specification" | cut -f 1 -
d "|")
691 source=$(echo
"$specification" | cut -f 2 -
d "|")
692 key=$(echo
"$specification" | cut -f 3 -
d "|")
693 default=$(echo
"$specification" | cut -f 4- -
d "|")
694 # Ermittlung des Funktionsaufrufs
695 if [
"$source" =
"function" ]; then
696 if [
"$rtype" =
"bool" ]; then
697 "$key" "$service_name" && value=
"true" || value=
"false"
699 value=$(
"$key" "$service_name")
702 if [
"$source" =
"value" ]; then
704 elif [
"$source" =
"detail" ]; then
707 msg_error "Unknown service attribute requested: $specification"
708 echo -n
"${separator}"
711 [ -z
"$value" ] && [ -n
"$default" ] && value=
"$default"
712 if [
"$rtype" =
"bool" ]; then
713 # Pruefung auf wahr/falsch
714 value=$(uci_is_true
"$value" && echo
"true" || echo
"false")
717 echo -n
"${separator}${value}"
719 # mit Zeilenumbruch abschliessen
725 ## @brief Ermittle den Namen der Log-Datei für diesen Dienst. Zusätzliche Details (z.B. "openvpn mtu") sind möglich.
726 ## @param service Name eines Dienstes.
727 ## @param other Eine beliebige Anzahl weiterer Parameter ist erlaubt: diese erweitern den typischen Log-Dateinamen für diesen Dienst.
728 ## @details Die Funktion stellt sicher, dass das Verzeichnis der ermittelten Log-Datei anschließend existiert.
730 trap
"error_trap get_service_log_filename '$*'" $GUARD_TRAPS
731 local service_name=
"$1"
733 local filename=
"$service_name"
734 while [ $# -gt 0 ];
do
735 filename=
"${filename}.$1"
738 local full_filename=
"$SERVICES_LOG_BASE/$(get_safe_filename "$filename
").log"
739 mkdir -p
"$(dirname "$full_filename
")"
740 echo -n
"$full_filename"
744 ## @fn get_service_log_content()
745 ## @brief Lies den Inhalt einer Log-Datei für einen Dienst aus.
746 ## @param service Name eines Dienstes.
747 ## @param max_lines maximale Anzahl der auszuliefernden Zeilen (unbegrenzt: 0)
748 ## @param other Eine beliebige Anzahl weiterer Parameter ist erlaubt: diese erweitern den typischen Log-Dateinamen für diesen Dienst.
749 ## @see get_service_log_filename
751 trap
"error_trap get_service_log_content '$*'" $GUARD_TRAPS
752 local service_name=
"$1"
756 [ -e
"$log_filename" ] ||
return 0
757 if [
"$max_lines" =
"0" ]; then
758 # alle Einträge ausgeben
761 # nur die letzten Einträge ausliefern
767 ## @fn is_service_routed_via_wan()
768 ## @brief Pruefe ob der Verkehr zum Anbieter des Diensts über ein WAN-Interface verlaufen würde.
769 ## @param service_name der Name des Diensts
770 ## @returns Exitcode == 0, falls das Routing über das WAN-Interface verläuft.
772 trap
"error_trap is_service_routed_via_wan '$*'" $GUARD_TRAPS
773 local service_name=
"$1"
774 # verwende die übergebene TypeOfService-Angabe oder (falls vorhanden/installiert) den
775 # TOS-Wert, der fuer nicht-Tunnel-Verkehr verwendet wird (typischerweise ist dies die
776 # die Intention des Anfragenden)
777 local tos_field=
"${2:-}"
778 [ -z
"$tos_field" ] && tos_field=
"${TOS_NON_TUNNEL:-}"
780 local outgoing_device
784 if is_device_in_zone
"$outgoing_device" "$ZONE_WAN"; then
785 msg_debug "target '$host' routing through wan device: $outgoing_device"
789 msg_debug "warning: target '$host' is routed via interface '$outgoing_device' (zone '$outgoing_zone') instead of the expected WAN zone ($ZONE_WAN)"
790 trap
"" $GUARD_TRAPS &&
return 1
795 _notify_service_success() {
796 local service_name=
"$1"
797 set_service_value
"$service_name" "status" "true"
798 set_service_value
"$service_name" "status_fail_counter" ""
799 set_service_value
"$service_name" "status_timestamp" "$(get_uptime_minutes)"
803 _notify_service_failure() {
804 local service_name=
"$1"
805 local max_fail_attempts=
"$2"
806 # erhoehe den Fehlerzaehler
808 fail_counter=$(( $(
get_service_value "$service_name" "status_fail_counter" "0") + 1))
809 set_service_value
"$service_name" "status_fail_counter" "$fail_counter"
810 # Pruefe, ob der Fehlerzaehler gross genug ist, um seinen Status auf
"fail" zu setzen.
811 if [
"$fail_counter" -ge
"$max_fail_attempts" ]; then
812 # Die maximale Anzahl von aufeinanderfolgenden fehlgeschlagenen Tests wurde erreicht:
813 # markiere ihn als kaputt.
814 set_service_value
"$service_name" "status" "false"
815 elif uci_is_true
"$(get_service_value "$service_name
" "status
")"; then
816 # Bisher galt der Dienst als funktionsfaehig - wir setzen ihn auf
"neutral" bis
817 # die maximale Anzahl aufeinanderfolgender Fehler erreicht ist.
818 set_service_value
"$service_name" "status" ""
820 # Der Test gilt wohl schon als fehlerhaft - das kann so bleiben.
823 set_service_value
"$service_name" "status_timestamp" "$(get_uptime_minutes)"
827 ## @fn run_cyclic_service_tests()
828 ## @brief Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist
829 ## @param test_function der Name der zu verwendenden Test-Funktion für einen Dienst (z.B. "verify_vpn_connection")
830 ## @param test_period_minutes Wiederholungsperiode der Dienst-Prüfung
831 ## @param max_fail_attempts Anzahl von Fehlversuchen, bis ein Dienst von "gut" oder "unklar" zu "schlecht" wechselt
832 ## @details Die Diensteanbieter werden in der Reihenfolge ihrer Priorität geprüft.
833 ## Nach dem ersten Durchlauf dieser Funktion sollte typischerweise der nächstgelegene nutzbare Dienst
834 ## als funktionierend markiert sein.
835 ## Falls nach dem Durchlauf aller Dienste keiner positiv getestet wurde (beispielsweise weil alle Zeitstempel zu frisch sind),
836 ## dann wird in jedem Fall der älteste nicht-funktionsfähige Dienst getestet. Dies minimiert die Ausfallzeit im
837 ## Falle einer globalen Nicht-Erreichbarkeit aller Dienstenanbieter ohne auf den Ablauf der Test-Periode warten zu müssen.
838 ## @attention Seiteneffekt: die Zustandsinformationen des getesteten Diensts (Status, Test-Zeitstempel) werden verändert.
840 trap
"error_trap test_openvpn_service_type '$*'" $GUARD_TRAPS
841 local test_function=
"$1"
842 local test_period_minutes=
"$2"
843 local max_fail_attempts=
"$3"
850 |
while read service_name;
do
853 if [ -z
"$status" ] || is_timestamp_older_minutes
"$timestamp" "$test_period_minutes"; then
854 if "$test_function" "$service_name"; then
855 msg_debug "service $service_name successfully tested"
856 _notify_service_success
"$service_name"
857 # wir sind fertig - keine weiteren Tests
860 msg_debug "failed to verify $service_name"
861 _notify_service_failure
"$service_name" "$max_fail_attempts"
863 elif uci_is_false
"$status"; then
864 # Junge "kaputte" Dienste sind potentielle Kandidaten fuer einen vorzeitigen Test, falls
865 # ansonsten kein Dienst positiv getestet wurde.
866 echo
"$timestamp $service_name"
868 # funktionsfaehige "alte" Dienste - es gibt nichts fuer sie zu tun
869 # Wir sortieren sie nach ganz oben, um bei Existenz eines lauffaehigen Diensts
870 # keine unnoetigen Tests von nicht-funktionierenden Hosts durchzufuehren.
871 echo
"-1 $service_name"
873 done | sort -n |
while read timestamp service_name;
do
874 # Mit dem Zeitstempel "-1" sind funktionierende Dienste markiert. Wir brauchen also keine
876 [
"$timestamp" =
"-1" ] &&
return 0
877 # Hier landen wir nur, falls alle defekten Gateways zu jung fuer einen Test waren und
878 # gleichzeitig kein Dienst erfolgreich getestet wurde bzw. als erfolgreich gilt.
879 # Dies stellt sicher, dass nach einer kurzen Nicht-Erreichbarkeit aller Gateways (z.B. olsr-Ausfall)
880 # relativ schnell wieder ein funktionierender Gateway gefunden wird, obwohl alle Test-Zeitstempel noch recht
882 msg_debug "there is no service to be tested - thus we pick the service with the oldest test timestamp: $service_name"
883 "$test_function" "$service_name" \
884 && _notify_service_success
"$service_name" \
885 || _notify_service_failure
"$service_name" "$max_fail_attempts"
886 # wir wollen nur genau einen Test durchfuehren
891 # Ende der Doku-Gruppe
get_hop_count_and_etx(host)
Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück.
uci_delete(uci_path)
Lösche ein UCI-Element.
get_service_log_filename()
Ermittle den Namen der Log-Datei für diesen Dienst. Zusätzliche Details (z.B. "openvpn mtu"...
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird...
notify_service()
Aktualisiere den Zeitstempel und die Entfernung (etx) eines Dienstes.
move_service_down(service_name, service_type)
Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach unten.
_get_local_bias_for_service()
Ermittle eine reproduzierbare Zahl von 0 bis (LOCAL_BIAS_MODULO-1, service_name) - abhängig von der l...
get_service_log_content(service, max_lines)
Lies den Inhalt einer Log-Datei für einen Dienst aus.
get_zone_of_device(interface)
Ermittle die Zone eines physischen Netzwerk-Interfaces.
filter_reachable_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die erreichbar sind.
filter_enabled_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die nicht manuell ausgeblendet wurden...
move_service_top(service_name, service_types)
Verschiebe einen Dienst an die Spitze der Dienst-Sortierung.
pipe_service_attribute(key, default)
Liefere zu einer Reihe von Diensten ein gewähltes Attribut dieser Dienste zurück. ...
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
run_cyclic_service_tests(test_function)
Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist...
sort_services_by_priority()
Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste...
filter_services_by_value(key, value)
move_service_up(service_name, service_type)
Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach oben.
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
set_service_detail(service_name, key, value)
Setze den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts.
print_services(service_type)
menschenfreundliche Ausgabe der aktuell angemeldeten Dienste
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
set eu on function print_services services log for dir in etc on services d var on services volatile d
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
msg_error(message)
Die Fehlermeldungen werden in die Standard-Fehlerausgabe und ins syslog geschrieben.
get_service_detail(service_name, key, default)
Ermittle den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts. ...
is_service_routed_via_wan(service_name)
Pruefe ob der Verkehr zum Anbieter des Diensts über ein WAN-Interface verlaufen würde.
update_service_routing_distance(service_name)
Aktualisiere Routing-Entfernung und Hop-Count eines Dienst-Anbieters.
get_service_name()
Ermittle en Namen eines Diensts basierend auf den Dienst-Attributen.
get_target_route_interface(target)
Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde.
is_existing_service(service_name)
Prüfe ob ein Service existiert.