IcqLib

Katzenbauer

Erfahrenes Mitglied
Wie ich bereits hier angekündigt habe arbeite ich schon seit einiger Zeit an einer php Libary. Ich habe mich dazu entschieden das ganze Ding in eine Klasse zu packen, weil das mir am praktischsten erscheint. Leider verwende ich aus Kompatibilitätsgründen noch nicht die neuen PHP5 Schlüsselwörter (leider). Ich bin bisher nur sehr langsam voran gekommen, weil es da doch einige Knackpunkte gab wo man ziemlich lange dran knobelt, wenn man sich noch nicht so lange mit Netzwerkprogrammierung beschäftigt und das Teil dann erstmal frustriert für ein paar Tage in die Ecke schmeißt. Außerdem gibt es da noch einige sehr php spezifische Stolpersteine.

Zudem überarbeite ich das Teil stetig, verbessere Kommentare, Error Handling, weil ich vorhabe das Teil unter der GPL zu releasen und sich deshalb andere Programmierer darin effizient zurecht finden sollen. Und da der Code (meiner Meinung nach) nicht grade trivial ist möchte ich, dass mir das so gut wie möglich gelingt. Da es mein erstes OpenSource Projekt ist, habe ich mich bisher nie um Dokumentationen geschert. Ich habe beschlossen den PHPDocumentor zu benutzen. d.H Erstmal wieder die Kommentare erweitern/umstellen. Ich frage mich ob ich damit nur öffentliche Methoden (also die, die man auch wirklich braucht) oder auch die Methoden die nur innerhalb der Klasse verwendet werden, dokumentieren soll, weil der Anwender will ja nur das nötigste wissen und sich dann an die Arbeit machen. Aber ich denke das könnte man doch auch einfach nur mit einer etwas ausführlicheren Readme abdecken, oder?

Wie dem auch sei ich bin noch lange nicht fertig. Ich bin jetzt erst fast mit der Login-Funktion fertig und habe bei stetiger Optimierung schon > 600 Zeilen (allerdings inkl. Komentare). Bis man sinvoll Nachrichten verschicken kann verdoppelt sich das bestimmt noch.

Und da liegt auch schon der Knackpunkt. Ich mache mir im Moment Gedanken wie ich das sinvoll umsetzen kann, weil es gibt einige Punkte, die einem php Script Probleme bereiten.
Ein Problem stellt uns zunächst mal der Icq Server, der festlegt wieviele Logins, Nachrichten, etc. maximal in einer bestimmten Zeitspanne hintereinander gesendet werden können. Wenn man ein bestimmtes Limit überschreitet trennt der Server die Verbindung hart und sperrt die Benutzernummer für ein paar Minuten, was natürlich fatal wäre. Würde man dann noch weiter machen verlängert sich die Sperrzeit nur noch. Deshalb fällt folgende Implementierung z.B in einem stark frequentierten Browsergame weg, wenn z.B eine Icq Nachricht gesendet werden kann, wenn man angegriffen wird:

PHP:
 <? 
$icq->login();
$icq->send_message("Hallo $user, deine Insel $koords steht unter Beschuss.");
$icq->logout();
?>

Wenn man nicht wegen der oft hintereinander folgenden Logins gekillt wird (was meistens schon nach 5 Stück passiert), dann, wenn man zuviele Nachrichten schickt. Dann werden Nachrichten, die man schickt einfach nicht mehr weitergeleitet.

Eine Lösung muss also her für dieses Problem. Das größte Problem ist bisher wie man es umgeht, dass man sich bei jedem Scriptaufruf neu einloggen muss. Wenn man eine Verbindung über fsockopen() aufbaut, dann wird diese automatisch nach Ende des Scriptaufrufs beendet und man müsste sich wieder neu einloggen. Eine mögliche Lösung ist die Funktion pfsockopen(). Sie hält die (Tcp) Verbindng auch nach Scriptausführung aufrecht (wenn man nicht fclose() macht). Das heißt, dass der Webserver auch nach Ablauf des Scriptes (also theorethisch 24/7) im Icq Online sein könnte und man so die Verbindung nur bei Bedarf neu aufbaut und man sich von da an nur noch um das Problem kümmern müsste wie man es veranlasst, dass nicht zu viele Nachrichten auf einmal geschickt werden (darauf komme ich später zurück).

Jedoch tuen sich bei einer permanenten Verbindung weitere Probleme auf. Wie stelle ich fest, dass schon eine Verbindung zum Icq Server besteht und ich direkt eine Nachricht senden kann ohne mich vorher einzuloggen? Also wie stelle ich fest, dass ich schon eingelogged bin. Auch habe ich manchmal das Problem, wenn die Verbindung nicht nach Scriptaufruf beendet (also permanent ist) wird (entweder durch pfsockopen() und kein fclose() oder das Script durch einen Error mittendrin abgebrochen wird (durch php) und er so nicht bis zum fclose() nicht kommt), dass dann noch irgendwelcher Müll im Stream-Buffer (ich nenn das mal so) befindet und sich dann, wenn man einen neuen Scriptaufruf macht der sich vor das neu Empfangene schiebt(natürlich steht es einfach nur davor weil es noch vom letzten Aufruf drinsteht) und so natürlich das Script zum Abruch bringt, weil diese Daten dann natürlich zu dem Zeitpunkt nicht erwartet werden und die Funktion abgebrochen wird. Vielleicht gibt es hier einen Spezialisten auf dem Gebiet, der mal was dazu sagen kann:)

Zu dem Problem, dass zu viele Nachrichten geschickt werden habe ich mir folgende Lösung überlegt:
Und zwar schickt der Server jedem Clienten (also auch meinem Script) beim einloggen ein Packet, welches für jeden Service Informationen enthält (Login, Nachrichten etc.) wie das sogenannte "Flow-Limit" festgelegt ist. Dieses wird im Moment noch nicht verwaltet, weil das fast 1KB Daten sind und das sehr sehr viel Arbeit wird das zu parsen und gescheit zu speichern. Da muss ich mich erstmal genauer mit beschäftigen.
Die Klasse könnte also bei jeder geschickten Nachricht das Flow-Limit überprüfen und, wenn noch neue Nachrichten geschickt werden können einfach die Nachricht abschicken ansonsten wird die Nachricht in eine Art Buffer geschrieben(Textdatei) und nichts passiert. Ein Cronjob könnte dann dafür sorgen, dass die Nachrichten abgeschickt werden. In dem befindet sich eine Schleife die, die Nachrichten im Buffer durchgeht und falls noch neue Nachrichten gesendet werden können die absendet (es muss halt nur dafür gesorgt werden, dass sie nicht zu schnell hintereinander geschickt werden). Für Seiten, die ein sehr großes Nachrichtenaufkommen haben könnte man dann mehre Accounts eintragen und der Cronjob wechselt dann den Account, wenn er zu viele Nachrichten geschickt hat (bevor der Account gemuted wird). Laufzeit des Scripts sollte man natürlich mit Zeitabstand zwischen den Aufrufen abstimmen, damit es einerseits fast immer läuft und andererseits nicht aufgerufen wird, wenn es bereits läuft.

Ihr seht ein ziemlich komplexes Thema. Wenn ihr Tipps habt oder euren Senf dazu abgeben wollt wie ihr es machen würdet dann bitte her damit, denn dafür habe ich dieses Posting erstellt. Ich hoffe es macht sich überhaupt jemand die Mühe und liest sich das durch.
 
Hi.

Ich hab mich ja in der Zwischenzeit auch mit ein paar Protokollen in Zusammenhang mit PHP auseinander gesetzt und find es echt gut, dass Du Dir die wahnsinnig umfangreiche Arbeit machst mal ICQ zu implementieren.
Das Thema kam ja schon ein paar Mal auf, und einmal hab ich mir die Kommunikation zwischen Client und Server angesehen und daraufhin beschlossen, dass ich da keine Lust drauf habe. Allein bis zum Login wird ja schon ein riesen Haufen Pakete geschickt.

Zum Thema persistente Verbindung werde ich mal ein wenig recherchieren und Dir dann meine Erkenntnisse mitteilen.
 
Um das Problem mit der Anzahl der maximal versendbaren Nachrichten in den Begriff zu bekommen, könntest du die einzelnen Nachrichten, die in deiner Übergangsdatenbank gespeichert sind, nach User sortieren.
Wenn dann dein Cronjob Nachrichten verschickt, könnte er jene, die an den gleichen User gehen, ja zusammenfassen. Das würd zB. bei Browsergame-Benachrichtigungen wahrscheinlich einige Nachrichten sparen.
Ansonsten: Weiter so! Tolle Idee!
 
Wollte mich auch mal an soetwas ransetzten. Hab aber aufgegeben, nachdem er mir nicht einmal UIN und Passwort annehemen wollte.

@Katzenbauer
Kannst du mir mal zeigen, wie du UIN und Passwort an den Server geschickt hast? Ich glaube, da hab ich irgendwas falsch gemacht. Dann kann ich das mal mit meinem vergleichen.

Und woher wisst ihr, was der Server alles benötigt um einen zu authen? Da hab ich nämlich nicht weitergeforscht, nachdem dass schon nicht klappen wollte
 
Hier hat jemand ganze Arbeit geleistet und eine Menge über das Protokol herausbekommen:
http://iserverd1.khstu.ru/oscar/

Ich zitiere mal kurz was da zum Passwort steht (bei der Methode, die ich verwende):

Passwords are roasted when sent to the host. This is done so they aren't sent in "clear text" over the wire, although they are still trivial to decode. Roasting is performed by first xoring each byte in the password with the equivalent modulo byte in the roasting array ( 0xF3, 0x26, 0x81, 0xC4, 0x39, 0x86, 0xDB, 0x92, 0x71, 0xA3, 0xB9, 0xE6, 0x53, 0x7A, 0x95, 0x7C )

Ich habe mir aus diesen Informationen dann folgende Funktion gebaut(die auch funktioniert):
PHP:
function roast_password($pw)
{
	 $roast = array(0xF3, 0x26, 0x81, 0xC4, 0x39, 0x86, 0xDB, 0x92, 0x71, 0xA3, 0xB9, 0xE6, 0x53, 0x7A, 0x95, 0x7C);
 
	 $roastet_password = '';
 
	 for ($i = 0; $i < strlen($pw); $i++)
	 {
		 $roastet_password .= chr($roast[$i] ^ ord(substr($pw, $i, 1)));
	 }
 
	 return $roastet_password;
}

PS: Sobald das Teil soweit ist, dass es Nachrichten verschicken kann werde ich es schonmal releasen ohne persistente Verbindung, Buffer etc. Getreu dem Motto "Release early, release often.". Auch, wenn es im Produktivbetrieb dann noch nicht zu gebrauchen ist, kann ma es dann schonmal testen.
 
Zuletzt bearbeitet:
Cool. Danke für die gute Seite. Ich glaube ich werde mich dann auch mal wieder an meinem Script versuchen. Mal schauen. Wer weiß, vll kann ich ja dir mal bei der ein oder anderen Sache dann helfen :)

mb fanste

PS: Hast du beim Login darauf geachtet, dass das Passwort nur eine bestimmte Länge haben darf? Also ich mein die maximale Länge. Acht Zeichen sind das glaube ich.
 
Also in PHP überprüfe ich das nicht, weil der Server meckert ja selber an, wenn das Passwort falsch ist(was ich dann in den Fehlerstring der Klasse schreibe).
 
Ah, ok.

Noch zu der Seite. Ich habe doch ein Problem. Ich blick da irgendwie net ganz durch :D . Liegt warscheinlich an meinen mieserablen Englischkenntnissen ;). Muss ich doch noch schauen, ob ich was deutsches find.
(Den HEX Code (Header) für den Login hab ich. Nur gesenden bekomm ich ihn nicht :) . Finds passende im Text nicht.)
 
Dennis Wronka hat gesagt.:
Das Thema kam ja schon ein paar Mal auf, und einmal hab ich mir die Kommunikation zwischen Client und Server angesehen und daraufhin beschlossen, dass ich da keine Lust drauf habe. Allein bis zum Login wird ja schon ein riesen Haufen Pakete geschickt.

Hi Dennis,

ich frage mich immer warum so wenige mit XMPP (Jabber & Co.) arbeiten.
The communication is a breeze -> well-formed xml ;)

Warum ICQ verwenden, wenn die Nutzung von ICQ der Firma AOL alle Rechte an den übermittelten Daten verschafft. (siehe AGB)
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück