 |
| 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 KonfigurationsdateienNormalerweise 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 festlegenEin 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-FunktionenDie 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üsselungEncodeB64(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-BehandlungDie 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-FunktionenDie 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.
|