Home

Benchmarks
Historie
Forum
Download
Helpware
Insider
Dokumentation
Kurs
Provider-Infos

Impressum



tdbengine - news vom 12.12.2001

Evolution statt Revolution: Bei der Weiterentwicklung der tdbengine wird nachwievor höchstes Augenmerk auf Stabilität und Performance gelegt Durch die wachsende Akzeptanz der tdbengine (auch in SQL-Kreisen) und deren Einsatz jenseits von Trivial-Datenbanken kommt nun ein weiterer Aspekt zum Tragen: SIcherheit - sowohl bei der Authentifizierung als auch bei der Datenübertragung und beim Speichern von Informationen auf dem Server. In der nunmehr vorliegenden Version 6.2.7 finden Sie deshalb die ersten Umsetzungen in dieser Richtung.

Sie werden sich vielleicht fragen, was die schon lange in Aussicht gestellte Implementierung der FASTCGI-Schnittstelle macht. Dazu ist zu bemerken, dass hier der Leidensdruck einfach noch nicht stark genug angewachsen ist. Die tdbengine als ganz normale CGI-Applikation schlägt sich auch unter extremen Stress-Bedingungen ganz hervorragend, leistungsfördernder Speicher ist spottbillig und die Computer werden auch immer schneller (zumindest unter Linux und FreeBSD). Aus diesen Gründen : FASTCGI ist zwar keineswegs aufgehoben, aber doch weiter aufgeschoben.

Mit Nachdruck arbeiten wir hingegen an einem erweiterten Dateiformat für Tabellen, Memos und Indizies: Transaktionen, Journal, Spiegelung - das sind hier die relevanten Themenkomplexe. Aber auch an dieser Stelle sei gesagt: Das neue Dateiformat kommt erst dann, wenn es in unseren Köpfen und in einer langen Testpraxis gereift ist.

Hier nun also die Änderungen und Erweiterungen der neuen Version.

Viel Spaß und Erfolg mit der tdbengine wünscht wie immer

Ulrich Kern


Änderungen bei der Konfiguration

Lokale Konfigurationsdateien

Normalerweise verwendet die tdbengine die Konfigurationsdatei aus dem gleichem Verzeichnis, in dem auch das ausführbare Programm selbst liegt.

Bevor ein Programm ausgeführt wird, wechselt die tdbengine in dasjenige Verzeichnis, in dem das Programm enthalten ist. Befindet sich in diesem Verzeichnis eine Datei tdbengine.ini, so wird diese als (ausschließliche) Konfigurationsdatei verwendet.

Das hat viele Vorteile:

* lokale Konfigurationsdateien sind übersichtlicher
* die Konfigurationsdatei kann für ein Projekt maßgeschneidert werden
* bei der Weitergabe an Dritte ist die Konfiguration im Projekt enthalten

Logdateien festlegen

Ein zusätzlicher Eintrag in der Konfigurationsdatei erlaubt es, Logfiles in andere Dateien als cgi.log zu schreiben.

[globals]
logcgi=1
log=/var/log/tdbengine/tdbengine.log

Damit wird das Logfile in die angegebene Datei geschrieben.

Zusätzlich kann dieser Eintrag jedem Programm zugeordnet werden, wodurch für einzelne Programme oder Programmgruppen separate Logfiles geschrieben werden:

[globals]
logcgi=1
log=/var/log/tdbengine/tdbengine.log
[admin]
log=./admin.log

Bitte beachten: logcgi ist (derzeit) nur unter [globals] erlaubt, genauso wie semadir.


Neue Funktionen:

Neue Ramtext-Funktionen

Die tdbengine stellt jetzt einen weiteren System-Ramtext unter dem Namen "ramtext:~clip" zur Verfügung. Dieser ist anfangs leer, kann aber mit allen bisher bekannten Mitteln gelesen und geschrieben werden. Zusätzlich wirken noch folgende Funktionen ganz speziell auf diesen Ramtext:

ramtext_delete(ramtext : STRING; startpos, anzahl : INTEGER) : INTEGER

Diese Funktion ist bereits bekannt: Sie löscht aus einem Ramtext ab der Startposition eine vorgegebene Menge von Zeichen. Diese Zeichenmenge wird nunmehr aber vor dem Löschen in den Ramtext "ramtext:~clip" kopiert (also wie bei der berühmten Zwischenablage).

ramtext_copy(ramtext : STRING; startpos, anzahl : INTEGER) : INTEGER

Das ist eine neue Funktion. Sie macht das Gleiche wie "ramtext:_delete", nur dass die Zeichen nicht gelöscht, sondern nur nach "ramtext:~clip" kopiert werden.

Und schließlich noch

ramtext_paste(ramtext : STRING; startpos : INETEGER) : INTEGER

Hier wird der Inhalt von "ramtext:~clip" in den Ramtext ab der Startposition "startpos" komplett eingefügt.
 

Codierung und Verschlüsselung

EncodeB64(s : STRING) : STRING // verschüsselt einen String mit Base64
DecodeB64(s : STRING) : STRING // entschlüsselt einen String mit Base64

Die Base64-Codierung ist der Standard bei der E-Mail-Übertragung von binären Dateien. Dabei werden aus drei Quell-Bytes vier Ziel-Bytes erzeugt, wobei die Zielbytes allesamt Zeichen im druckbaren Bereich ergeben.

Beispiel:
 
PROCEDURE Main
VAR s_in, s_out, s_test : STRING
  cgiwriteln('content-type: text/plain')
  cgiwriteln('')
  s_in:='Ulrich Andreas Kern'
  s_out:=EncodeB64(s_in)
  s_test:=DecodeB64(s_out)
  cgiwriteln(s_in)
  cgiwriteln(s_out)
  cgiwriteln(s_test)
ENDPROC

Ausgabe:

Ulrich Andreas Kern

VWxyaWNoIEFuZHJlYXMgS2Vybg==

Ulrich Andreas Kern

Routinen zur Passwort-Behandlung

Die tdbengine stellt nun zwei Routinen aus der Crypt-Bibliothek zur Verfügung:

MakePW(s : STRING) : STRING // verschlüsselt ein Passwort im Unix-Standard
TestPW(s, vgl : STRING) : 0|1 // prüft, ob vgl eine Verschlüsselung von s ist

Beispiel:
 
PROCEDURE TestUser(file, id, pw : STRING) : INTEGER
/* Funktion zur Überprüfung einer id-pw-Kombination.
  file: passwd-Datei, die mit htpasswd (Apache) unter Linux erzeugt wurde
  Rückgabewert: 1 : User okay
                0 : No match
*/
VAR t : INTEGER = reset(file)
VAR l, vgl : STRING
  WHILE NOT EOT(t) DO
    IF pos(id+':',l:=readln(t)) THEN
      close(t)
      IF testpw(pw,l[length(id)+2,255])
      THEN RETURN 1
      ELSE RETURN 0
      END
    END
  END
  close(t)
  RETURN 0
ENDPROC

Einfache Socket-Funktionen

Die folgenden vier Funktionen sind in allen Versionen der tdbengine verfügbar. Mit ihnen ist es möglich, Klients aus allen Bereichen zu schreiben.

OpenSock(adr : STRING) : INTEGER // öffnet einen TCP-Stream-Socket

adr ist ein String der Form: IP:Port wie '192.168.1.100:80' oder auch
'mail.tdb-engine.de:25'

Rückgabewert ist ein Socket-Handle (1 bis 32)

CloseSock(s : INTEGER) : INTEGER // schließt einen offenen Socket

s : Handle von OpenSock
 

GetSock(s : INTEGER; VAR p : CHAR[]; maxchars : INTEGER) : INTEGER;
GetSock(s : INTEGER; VAR p : BYTE[]; maxbyte : INTEGER) : INTEGER;

Überträgt aus dem Socket maxchars Zeichen bzw. maxbyte Bytes in die Array-Variable p.

Rückgabewert: Anzahl der wirklich übertragenen Zeichen/Bytes.
 

PutSock(s : INTEGER; VAR p : CHAR[]; maxchars : INTEGER) : INTEGER;
PutSock(s : INTEGER; VAR p : BYTE[]; maxbyte : INTEGER) : INTEGER;

Überträgt zu dem Socket maxchars Zeichen bzw. maxbyte Bytes aus der Array-Variablen p.

Rückgabewert: Anzahl der wirklich übertragenen Zeichen/Bytes.

Kleines Programmbeispiel (bitte nicht unverändert ausprobieren, ich krieg schon so genügend Mails)
 
PROCEDURE send_str(s : INTEGER; l : STRING);
VAR p : CHAR[1000];
  p[0]:=l+^M+^J; PutSock(s,p,length(l)+2)
  cgiwriteln('> '+l)
ENDPROC

PROCEDURE recv_str(s : INTEGER) : STRING;
VAR p : CHAR[1000];
VAR i : INTEGER;
VAR res : STRING;
  nloop(i,GetSock(s,p,1000)-1,res:=res+p[i]);
  RETURN res
ENDPROC

PROCEDURE Main;
VAR p : CHAR[1000];
VAR i : INTEGER;
  cgiclosebuffer;
  cgiwriteln('content-type: text/plain');
  cgiwriteln('');
  IF i:=OpenSock('mail.tdb-engine.de:25') THEN
    cgiwriteln(recv_str(i));
    send_str(i,'HELO mail.tdb.de');
    cgiwriteln(recv_str(i));
    send_str(i,'MAIL FROM:hk@tdb.de');
    cgiwriteln(recv_str(i));
    send_str(i,'RCPT TO:uli@tdb-engine.de');
    cgiwriteln(recv_str(i));
    send_str(i,'DATA')
    cgiwriteln(recv_str(i));
    send_str(i,'Das ist ein kleiner Test.');
    send_str(i,'Und das ist die zweite Zeile');
    send_str(i,'.');
    cgiwriteln(recv_str(i));
    send_str(i,'QUIT');
    cgiwriteln(recv_str(i));
    CloseSock(i)
  ELSE
    cgiwriteln('done.')
  END
ENDPROC

Und so ist die Ausgabe des Programms:
 
220 www.tdb-engine.de ESMTP Sendmail 8.10.2/8.10.2/SuSE Linux ...

> HELO mail.tdb.de

250 www.tdb-engine.de Hello [62.208.108.251], pleased to meet you

> MAIL FROM:hk@tdb.de

250 2.1.0 hk@tdb.de... Sender ok

> RCPT TO:uli@tdb-engine.de

250 2.1.5 uli@tdb-engine.de... Recipient ok

> DATA

354 Enter mail, end with "." on a line by itself

> Das ist ein kleiner Test.

> Und das ist die zweite Zeile

> .

250 2.0.0 f9GE7Kj09453 Message accepted for delivery

> QUIT

221 2.0.0 www.tdb-engine.de closing connection

Alle Socket-Funktionen führen im Fehlerfall zu einem (behandelbaren) Laufzeitfehler.

GetSock und PutSock liefern im Fehlerfall negative Ergebnisse, OpenSock den Wert 0.


tdbengine als Unix-Scriptsprache

Und noch eine schöne Neuerung (nur unter Linux/FreeBSD praktikabel):

EASY-Programme können unter Linux/FreeBSD jetzt (auch) als "normale" Scripten aufgefasst werden.

Dazu wird, wie bei der Shell, Perl und anderen Scriptsprachen, in der ersten Zeile der Interpreter angegeben:
 
#!/home/tdbengine/bin/tdbengine

oder, wenn eine Kopie der tdbengine in /usr/local/bin liegt:
 
#!/usr/local/bin/tdbengine

Dann wird das EASY-Script ausführbar gemacht und kann anschließend einfach wie jedes andere Programm auch gestartet werden.
Dadurch wird die tdbengine mit dem Script als Parameter gestartet. Anhand der ersten Zeile erkennt nun die tdbengine, dass es sich dabei um ein direkt auszuführendes Script handelt, übersetzt dieses und führt schließlich die Prozedur "Main" aus.

Beispiel:
 
#!/home/tdbengine/bin/tdbengine
VAR spooldir : STRING = '/var/spool/outgoing_mails'

PROCEDURE clear_spooler
VAR l : STRING = firstdir(spooldir+'/*.msg','')
VAR fn, s_to, s_from, host : STRING
VAR p,q : INTEGER
  host:=getenv('SERVER_NAME')
  WHILE l DO
    fn:=rtrim(l[1,63])
    loadtemplate(spooldir+'/'+fn)
    IF p:=ramtext_find('ramtext','To: ') THEN
      q:=ramtext_find('ramtext',^J,p+1)
      IF q-p<255 THEN
        s_to:=ramtext_part('ramtext',p+4,q-p-4)
      END
    END
    IF p:=ramtext_find('ramtext','From: ') THEN
      q:=ramtext_find('ramtext',^J,p+1)
      IF q-p<255 THEN
        s_from:=ramtext_part('ramtext',p+6,q-p-6)
      END
    END
    IF s_to, s_from THEN
      CGIExec('sendmail -v -pSMTP:'+host+' -f '+s_from+' '+s_to+' < '+spooldir+'/'+fn+' >> '+spooldir+'/mail.log')
      delfile('mails/'+fn)
    END
    l:=nextdir
  END
ENDPROC

PROCEDURE Main
  EndSema
  REPEAT
  pause(1000)
    clear_spooler
  UNTIL 0
ENDPROC

Speichern unter /usr/local/sbin/mailer
Ausführbar machen: chmod a+x /usr/local/sbin/mailer

Dann einmal starten:

sudo -b /usr/local/sbin/mailer

...und schon haben wir einen Mail-Versender, der alle zehn Sekunden Mails aus dem Spoolverzeichnis verschickt und dabei ein sauberes Log-File schreibt.

Freilich könnte man das auch mit

/home/tdbengine/bin/tdbengine mailer.prg

machen, aber

1. entfällt hier der Compilierungsvorgang (er erfolgt sozusagen on the fly)
2. bleibt hier absichtlich der Script-Quelltext das tragende Element und ist somit permanent verfüg- und damit wartbar
3. erhöht die Anlehnung an der Standard (hoffentlich) die Akzeptanz der tdbengine (Scriptsprache mit eingebauter Datenbank)


Weitere Verbesserungen

LoadTemplate mit http-Adressen funktioniert jetzt auch in der Windows-Version.

Beispiel:

IF LoadTemplate('http://www.irgendeinedomain.de/templates/irgendeintamplate.html')=0
THEN ... // Template ist da
ELSE ... // Fehlermeldung
END
...

Diese Funktion ist nicht zu unterschätzen, erlaubt sie doch nicht nur (wie bisher) die funktionale, sondern (nunmehr) auch die räumliche Trennung von (CGI-)Programmierung und (HTML-)Design

Die Funktion SetIdent wurde neu kodiert ist ist jetzt in der Ausführung wesentlich (Faktor 10) schneller. Zudem erzeugt sie Zeilenvorschübe je nach Betriebssystem: LF bei Linux und FreeBSD, CRLF bei Win32.


Hinweise zur Fehlersuche

Die tdbengine ist wieder einmal ein bisschen strenger geworden. Diesmal geht um das Lesen und Schreiben von Ramtexten:

reset(Ramtext) liefert einen Laufzeitfehler (1), wenn der Ramtext bereits zum Schreiben geöffnet ist.
rewrite(Ramtext) liefert einen Laufzeitfehler (1), wenn der Ramtext bereits zum Lesen geöffnet ist.
 

Newsletter

Anmeldung zum Newsletter:
Name: 
Zusatz: 
EMail: