Leopold–Franzens–Universität Innsbruck Improvement of XMPP
Transcription
Leopold–Franzens–Universität Innsbruck Improvement of XMPP
Leopold–Franzens–Universität Innsbruck Institut für Informatik Forschungsgruppe DPS (Distributed and Parallel Systems) Improvement of XMPP support in ECF Bachelorarbeit Betreuer: Max Berger Roland Matha’ (0615172) [email protected] Innsbruck 28. Jänner 2010 Zusammenfassung In dieser Arbeit wird das Einbinden neuer Funktionalitäten in ein bereits bestehendes Projekt (ECF) beschrieben. Einerseits werden die Begriffe XMPP, SmackAPI ,ECF und Link-Local-Messaging(XEP-0174) erklärt und deren Funktionsweise beschrieben. Andererseits wird die Implementierung eines Link-Lokal-Clients beschrieben. Dabei wird auf Probleme bei der Einbindung, sowie auf weiterführende Erweiterungen eingegangen. Inhaltsverzeichnis 1. Einleitung 1.1. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. Ziel der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3. Gliederung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 2 2 2. XMPP 2.1. Was ist XMPP? . . . . . . . . . . . . . . 2.2. Kommunikation über XMPP . . . . . . 2.2.1. Jabber-ID . . . . . . . . . . . . . 2.2.2. XML-Stream und XML-Stanzas 2.3. Bestehende Ansätze . . . . . . . . . . . 2.3.1. SmackAPI . . . . . . . . . . . . . 2.4. Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 5 5 7 7 8 3. SmackAPI 2.2 im ECF updaten 3.1. Was ist ECF? . . . . . . . . . . 3.2. Problemstellung . . . . . . . . . 3.3. Neuerungen von SmackAPI 3.1 3.4. Integration ins ECF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 . 9 . 9 . 9 . 10 4. Link-Local Messaging (XEP-174) 4.1. Was ist Link-Local Messaging? 4.1.1. DNS Reords . . . . . . . 4.1.2. TXT Record . . . . . . 4.1.3. Nachrichtenaustausch . 4.2. Bestehende Ansätze . . . . . . 4.3. Problemstellung . . . . . . . . . 4.4. Verwendete Ansätze bzw. APIs 4.4.1. DNS-SD . . . . . . . . . 4.4.2. Eclipse-Plugin . . . . . 4.4.3. SAXParser . . . . . . . 4.5. Implementierung . . . . . . . . 4.5.1. BonjourRosterView . . 4.5.2. Chat . . . . . . . . . . . 4.5.3. ChatManager . . . . . . 4.6. Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 11 11 12 13 13 13 14 14 15 16 16 16 17 18 19 5. Zusammenfassung und Ausblick 20 5.1. Vorschläge zur Erweiterung . . . . . . . . . . . . . . . . . . . . . 20 iv Literaturverzeichnis 22 A. Anhang 23 A.1. Aufbau des Eclipse Workbench . . . . . . . . . . . . . . . . . . . 23 Abbildungsverzeichnis 2.1. Jabber-Netzwerk mit Transport zu ICQ/AIM . . . . . . . . . . . 4 A.1. Aufbau des Eclipse Workbench [4] . . . . . . . . . . . . . . . . . 23 1 1. Einleitung Das Chatten über ICQ erfreut sich bereits seit einigen Jahren großer Beliebtheit. Die Entwicklung und Verbesserung solcher Chatprotokolle ist aber noch lange nicht am Ende und so gibt es ständig Neuerungen. Eines der aktuellsten Protokolle für Instant Messaging(IM) ist sicherlich XMPP. Es ist einfach zu handhaben und es ermöglicht das Chatten mit proprietären Netzwerkprotokollen, wie etwa ICQ, ohne zusätzlichen Aufwand für den Chatclient. Dafür sorgen so genannte Transports am Server, d.h. der Client muss ”nur” XMPP-fähig sein und der Jabber-Server verarbeitet bzw. übersetzt die Nachrichten und leitet sie richtig weiter. 1.1. Motivation XMPP ist mithilfe einer API (SmackAPI) bereits im Eclipse Communication Framework (ECF) integriert und voll funktionsfähig. Das ECF ermöglicht ebenfalls das Chatten mit anderen bekannten Chatprotokollen, wie MSN, IRC, ... allerdings fehlt noch eine aktuelle Erweiterung, das so genannte Link-LocalMessaging. Link-Local-Messaging vereint die Stärken beider Techniken Zeroconf (Apples Name: Bonjour, ehemals Rendezvous), für die Service Discovery, und XMPP, für den eigentlichen Nachrichtenaustausch, in sich. Link-Local-Messaging hat deshalb den großen Vorteil, dass es serverlos arbeitet und nur ein Benutzernamen ausgewählt werden muss, um bereits mit jedem anderen Client, der im lokalen Netz als Chatclient sichtbar ist, kommunizieren zu können. 1.2. Ziel der Arbeit Ziel dieser Arbeit ist einerseits der Austausch der alten SmackAPI 2.2 durch die neue SmackAPI 3.1 im ECF. Andererseits besteht der Hauptteil der Arbeit darin einen Link-Local-Client zu schreiben und diesen, unter Verwendung der bereitgestellten Komponenten des ECF, ins ECF zu integrieren. 1.3. Gliederung Die Arbeit ist in folgende Kapitel gegliedert: Kapitel 2 erläutert den Begriff XMPP, beschreibt die Kommunikation über XMPP und gibt einen Überblick über bereits bestehende Ansätze 2 1.3 Gliederung Kapitel 3 beschreibt den Begriff ECF, die Neuerungen in SmackAPI 3.1 gegenüber der alten Version und geht auf den Austausch der SmackAPI im ECF ein. Kapitel 4 demystifiziert den Begriff ”Link-Local-Messaging”, beschreibt dessen Funtionsweise, geht kurz auf bereits bestehende Ansätze ein und erläutert die eigentliche Implementierung. Die für die Implementierung benötigten APIs, wie beispielsweise DNS-SD werden ebenfalls angeschnitten. Am Ende werden noch zusätzliche Vorschläge zur Erweiterung der Applikation gegeben. 3 2. XMPP Mit der steigenden Zahl an verschiedenen Chatprotokollen werden serverübergreifende Protokolle immer wichtiger. Eines, der aktuellsten serverübergreifenden Protokollen ist XMPP. Im folgenden wird XMPP, dessen Verwendung und Funktionsweise genauer beschrieben. Es werden Begriffe, wie Jabber-ID, XML-Stream und XML-Stanza erklärt und bereits bestehende Ansätze aufgezeigt. Bei den bereits bestehenden Ansätzen wird das Augenmerk auf der SmackAPI gerichtet. 2.1. Was ist XMPP? XMPP (Extensible Messaging and Presence Protocol) ist ein, auf XML basiertes, Nachrichten- und Anwesenheitsprotokoll und wurde 2004 von der IETF1 als RFC 3920-3923 veröffentlicht [10]. Es wird vor allem für Instant Messaging, Mehrbenutzerchat, Zertifikatversendung und Dateiübertragungen zwischen verschiedenen Plattformen verwendet [10]. 2.2. Kommunikation über XMPP XMPP verwendet zur Kommunikation, ähnlich wie das World Wide Web, ein Netzwerk aus unzähligen Servern, die eine Vielzahl an Diensten anbieten. Abbildung 2.1.: Jabber-Netzwerk mit Transport zu ICQ/AIM Damit XMPP funktioniert muss ein Server einen Jabber-Dienst, wie Ejabbered oder Openfire, anbieten. 1 4 http://www.ietf.org/ 2.2 Kommunikation über XMPP Ein so genannter Jabber-Server(z.B. ”example.org”) kann auch zusätzliche Dienste, wie etwa ICQ oder AIM anbieten. Hierbei wird ein wesentlicher Vorteil von XMPP ersichtlich, denn ein XMPP-Client (z.B. ”alice”) kann, mithilfe so genannter Transports (siehe Abb.2.1), mit proprietären NetzwerkprotokollClients (z.B. ICQ) kommunizieren. Die einzige Voraussetzung hierfür ist, dass der gewählte Server den notwendigen Transport unterstützt. Der Client selbst verwendet XMPP-fähige Instantmessanger, wie Pidgin oder Psi, um mit dem Server zu kommunizieren [5, S. 11]. Für die Kommunikation gibt es drei grundlegende Begriffe: • Jabber-ID: identifiziert den Client eindeutig • XML-Stream: Datenstrom zwischen Client und Server oder Server und Server • XML-Stanzas: gesendete Informationen über einen XML-Stream Im folgenden wird auf die drei Begriffe genauer eingegangen. 2.2.1. Jabber-ID Damit ein Client sich an einem XMPP-Server registrieren bzw. anmelden kann und innerhalb des XMPP-Netzwerkes somit eindeutig identifizierbar ist, wurde ein so genannter Jabber Identifier eingeführt. Der Aufbau einer Jabber-ID erinnert an den einer E-Mail-Adresse und ist hier als ABNF (Argumented Backus-Naur Form) aufgeführt [7]: jid = [ node ”@” ] domain [ ”/” resource ] domain = fqdn / address-literal fqdn = (sub-domain 1*(”.” sub-domain)) sub-domain = (internationalized domain label) address-literal = IPv4address / IPv6address Hierbei ist ”node” der Node Identifier und steht für den Accountnamen des registrierten Benutzers. Der Domainname ”domain”, des XMPP-Servers, wird durch ein ”@” vom Node Identifier getrennt angegeben. Eine Ressource ”resource” ist optional und kann vom Benutzer frei gewählt werden. Dadurch ist es möglich ein und den selben Accountnamen von mehreren Rechnern aus, gleichzeitig zu verwenden, weil der Server nun die verschiedenen Anmeldestandorte eindeutig unterscheiden kann [7]. 2.2.2. XML-Stream und XML-Stanzas Bisher wurde die Kommunikation in XMPP nur oberflächlich betrachtet. Die eigentliche Kommunikation funktioniert mit so genannten XML-Streams und den darin gesendeten bzw. empfangenen XML-Stanzas [7]. 5 2 XMPP XML-Stream ist ein Datenstrom bzw. Socket welches mit dem Start-Tag <stream> gestartet und mit dem dazugehörigen End-Tag </stream> geschlossen wird. Innerhalb dieser Tags erfolgt die eigentliche Kommunikation mithilfe so genannter XML-Stanzas [7]. XML-Stanza ist die eigentliche Information, formuliert in XML, die in einem XML-Stream gesendet bzw. empfangen wird. In XMPP gibt es drei zulässige XML-Stanzas [7]: • iq: ist eine Info/Query-Stanza und dient für Request/Respons-Anfragen (z.B. für Rosteranfragen) • presence: dient dazu den Status (online,away,...) von Chatclients zu erfragen, sowie den eigenen zu versenden • message: ist die eigentliche Chatnachricht, welche von den Clients gesendet und empfangen wird Listing 2.1: Beispiel eines XML-Streams und der gesendeten Stanzas <stream> ... <p r e s e n c e> <show>xa</show> <s t a t u s>b i n g e r a d e n i c h t h i e r</ s t a t u s> </ p r e s e n c e> ... <message from=” a l i c e @ e x a m p l e . o r g /home” t o=” a l i c e @ e x a m p l e . o r g / work ” type=” c h a t ”> <body>H a l l o</ body> </ message> ... <i q type=” g e t ”> <query xmlns=” j a b b e r : i q : r o s t e r ”> </ i q> ... </ stream> < !−−a−−> < !−−b−−> <!−−c−−> < !−−d−−> Im obigen Beispiel wird die Kommunikation eines Clients mit dem Server aufgezeigt. Das Beispiel ist nicht vollständig und dient nur zum besseren Verständnis der eben erklärten Begriffe und der somit verbundenen Arbeitsweise von XMPP. Bei Position a (siehe Listing 2.1) wird der XML-Stream mit dem entsprechenden Start-Tag gestartet. Bei Position b sendet der Client seinen eigenen Status mit der XML-Stanza presence. In diesem Fall wird der Status auf xa, d.h. extended away gesetzt, wodurch zusätzlich noch eine Textmeldung gesendet werden kann, die den aktuellen Status beschreibt [7]. Bei Position c wird mithilfe der XML-Stanza message eine Nachricht gesendet. Die eigentliche Nachricht befindet sich dabei im Body-Tag. Damit der Server die Nachricht richtig weiterleiten kann, müssen die Eigenschaften ”from”, ”to” und ”type” gesetzt sein, wobei ”from” die JID des Nachrichtensender, ”to” 6 2.3 Bestehende Ansätze die JID des Nachrichtenempfänger und ”type” den Typ der Nachricht angibt. Die gebräuchlichsten Message-Typen sind ”groupchat” (Multiuserchat), ”chat” (Standard-Chat) und ”error” (Fehlernachricht) [7]. Bei Position c stellt der Client eine Anfrage an den Server für den Erhalt seines Rosters. Der Typ der XML-Stanza ist dabei auf ”get”. Der Client erhält vom Server daraufhin entweder eine iq vom Typ ”result”, mit den Rostereinträgen des Clients, oder eine iq vom Typ ”error”, falls ein Fehler aufgetreten ist [7]. In diesem Abschnitt wurden die Begriffe Jabber-ID, XML-Stream und XMLStanza eingeführt und anhand eines Beispiels beschrieben. 2.3. Bestehende Ansätze Für die Implementierung eines XMPP-Clients gibt es eine Vielzahl an bereits vorhandenen APIs für die gebräuchlichsten Programmiersprachen. Eine genaue Auflistung aller bereitgestellten Libraries befindet sich auf der Homepage von XMPP2 . Explizit für Java sind bisher folgende APIs verfügbar [1]: • emite3 • Echomine Feridian • IP*Works Internet Toolkit4 • Jabber Stream Objects (JSO)5 • Tinder6 • Smack In dieser Arbeit wird nur auf die SmackAPI eingegangen, weil diese unter der ASL-Lizenz verfügbar ist und daher im Eclipse bzw. ECF verwendbar ist. 2.3.1. SmackAPI Die SmackAPI ist eine Open Source XMPP-Client Library von Jive Software, geschrieben in Java, für Instant Messaging und Presence [8]. Die aktuelle Version ist 3.1. Smack erleichtert das Senden von Nachrichten über XMPP ungemein. Das folgende Code-Beispiel enthält alle notwendigen Codezeilen um eine Nachricht von ”[email protected]” an ”[email protected]” zu schicken. 2 http://xmpp.org/software/libraries.shtml http://code.google.com/p/emite/ 4 http://www.nsoftware.com/ipworks/ 5 https://jso.dev.java.net/ 6 http://www.igniterealtime.org/projects/tinder/ 3 7 2 XMPP Listing 2.2: Alice sendet eine Nachricht an Heidi XMPPConnection c o n n e c t i o n = new XMPPConnection ( ” example . o r g ” ) ; connection . connect ( ) ; c o n n e c t i o n . l o g i n ( ” a l i c e ” , ” password ” ) ; Chat c h a t = c o n n e c t i o n . getChatManager ( ) . c r e a t e C h a t ( ” heidi@example . o r g ” , new M e s s a g e L i s t e n e r ( ) { public void p r o c e s s M e s s a g e ( Chat chat , Message message ) { System . out . p r i n t l n ( ” R e c e i v e d message : ” + message ) ; } }) ; c h a t . sendMessage ( ” H a l l o H e i d i ! LG A l i c e ” ) ; 2.4. Zusammenfassung In diesem Kapitel wurde der Begriff XMPP erklärt, dessen Funktionsweise beschrieben und bereits bestehende Ansätze analysiert. Die Kommunikation wurde anhand einer Abbildung und dem Vergleich zum World Wide Web erklärt. Weiters wurden die, für die Kommunikation grundlegenden, Begriffe Jabber-ID, XML-Stream und XML-Stanza eingeführt und anhand von Beispielen anschaulich erklärt. Bei den bereits bestehenden Ansätzen wurde vor allem auf die, in Java verfügbaren, SmackAPI eingegangen, die auch im folgenden Kapitel (siehe Kapitel 2.4) verwendet wird. 8 3. SmackAPI 2.2 im ECF updaten Eine Software bzw. API ist nie vollständig fehlerfrei. Obwohl die Hauptfunktionalitäten gewährleistet werden, können trotzdem Bugs im Code enthalten sein. Diese Bugs werden erst nach der Veröffentlichung, nach und nach, durch Patches und neue Versionen der Software behoben. Ein Programmierer sollte deshalb stets darauf bedacht sein die aktuellste Version einer API zu verwenden. 3.1. Was ist ECF? Das ECF ist ein Opensource Framework, um die Entwicklung von verteilten Tools und Anwendungen für Eclipse zu erleichtern. Die Verwendung ist Vielseitig und reicht von der Entwicklung anderer Plugins bzw. Tools bis hin zu vollständigen Eclipse RCP (Rich-Client-Plugin) Anwendungen. Für diese Arbeit ist vor allem wichtig dass ECF einen Chat, auf der Basis von Smack, bietet. 3.2. Problemstellung Das ECF verwendet eine veraltete Version der SmackAPI für die Kommunikation über XMPP. Die unterstützte Version ist 2.2 und soll auf die Version 3.1 gepatcht werden, weil verschiedene Neuerungen getroffen und Bugs behoben wurden. 3.3. Neuerungen von SmackAPI 3.1 SmackAPI stellt mit der aktuellen Version 3.1 verschiedene Neuerungen zur Verfügung. Die gesamten Neuerungen sind im Smack Changelog1 aufgelistet. In dieser Arbeit wird nur auf eine Auswahl an Updates eingegangen: • Wichtige Veränderungen: – Java 5 ist notwendig – mehrere Updates sind nicht rückwärts kompatibel (z.B. Connection handling und Klasse Chat) • Neue Features – Support für JEP-502 (Ad-hoc commands). – Das Laden des Rosters während des Logins ist optional – Mime Typen werden auch für den Avatar verwendet 1 2 http://www.igniterealtime.org/builds/smack/docs/3.1.0.beta1/changelog.html http://xmpp.org/extensions/xep-0050.html 9 3 SmackAPI 2.2 im ECF updaten – Mehrere Nachrichten Bodys und Body Sprachen werden unterstützt – Ein User mit dem Status ”offline” kann einen Statustext hinterlassen. – Erweiterter Support von Stream Errors: Smack benutzte bis dahin den, in Jabber-Netzwerken üblichen, Error Format. Mit Version 3.1 die unter http://www.xmpp.org/specs/rfc3920.html#stanzas-error definierten. • Bug Fixes – Entfernen des Status ”unsichtbar”: Der unsichtbare Presence Mode verletzt die XMPP RFC – Die Verbindungsgeschwindigkeit wurde erhöht – DNS Lookups arbeiten nun mit allen DNS Servern: In Version 2.2 wurde noch nach Records vom Typ (type) ”ANY” und der Klasse (class) ”ANY” gesucht. Ab Version 3.0 wird nach Records vom Typ ”SRV” und der Klasse ”IN” gesucht – Die Methode ”getPresence” arbeitete nicht korrekt beim Status ”offline”. 3.4. Integration ins ECF Die Integration der neuen SmackAPI ins ECF erfolgte in mehreren Schritten, wobei zwischen den Schritten verschiedene Zeitspannen lagen. Damit das Erstellen eines Patchs erst möglich wurde, musste die aktuelle Version des ECF Projekts über CVS bezogen und die SmackAPI 3.1 in Eclipse importiert werden. Nach geraumer Einarbeitung wurde der Patch erstellt und, über den Bugtracker von Eclipse und über die Mailing-List des ECF, veröffentlicht. Die Antwort, dass der Patch durchaus nützlich sei, folgte prompt, jedoch mussten die Lizenzvereinbarungen der SmackAPI erst geklärt werden. Ein halbes Jahr lang passierte nichts, bis einer der Committer die neue Version der SmackAPI benötigte und den Patch entdeckte. Der Patch wurde schließlich angewandt und wird vorraussichtlich in der neuen ECF Version verfügbar sein. 10 4. Link-Local Messaging (XEP-174) Das in RFC 3920 definierte XMPP unterstützt keine serverlose Kommunikation zwischen den Clients. Erst nach einer Authentifizierung am Server erhält der Client Zugang zum Jabber-Netzwerk [6]. Für die Kommunikation über ein lokales Netz, ist ein Server in der Regel überflüssig, weswegen ein neues Protokoll eingeführt wurde. 4.1. Was ist Link-Local Messaging? Link-Local Messaging vereint die Vorteile des Zeroconfiguration-networking1 mit den Prinzipien von XMPP. Vom Zeroconfiguration-networking wird vor allem die Service Discovery verwendet. In den folgenden Abschnitten werden die, für die Service Discovery benötigten, DNS Records beschrieben, wobei auf den TXTRecord genauer eingegangen wird, und der Nachrichtenaustausch erklärt. 4.1.1. DNS Reords Ein neuer Client muss sich nicht erst an einem Server anmelden und authentifizieren, sondern muss lediglich vier verschiedene DNS-Records im lokalen Netz veröffentlichen [6]: A Record oder Adress Record: IPv4-Adresse des Hosts, der Form: computer-name.local. A ip-address SRV Record oder Service Record: angebotener Dienst (Service), der Form: presence. tcp <ttl> IN SRV <priority> <weight> port-number [email protected]. PTR Record oder Pointer Record: Domain Name Pointer,um IP-Adressen Namen zuzuweisen, der Form: presence. tcp.local. port-number IN PTR username@computer-name. presence. tcp.local. TXT Record: Freidefinierbarer Text, der Form: <owner> IN <ttl> TXT ”jid=user-jabber-id” Der Service Typ ist für Link-Local Messaging ” presence. tcp”. Der Zusatz ”.local.” beschreibt dabei die Beschränkung aufs lokale Netz. 1 http://www.zeroconf.org/ 11 4 Link-Local Messaging (XEP-174) 4.1.2. TXT Record Für einen TXT Record gibt es, zusätzlich zum oben verwendeten Schlüsselwort ”jid”, noch eine Vielzahl anderer nützlicher Attribute. Hier eine Auflistung und Beschreibung der wichtigsten TXT Records [6]: 1st beschreibt den ersten (first) Namen des Clients email die E-Mail-Adresse des Benutzers jid die Jabber-ID des Clients last der letzte Name des Benutzers msg eine Textnachricht, welche den aktuellen Status des Users beschreibt port.p2pj Port des Users. Der Port des Users sollte jedoch nur vom SRV Record verwendet werden und nicht vom TXT Record. status kann die Werte ”avail” (online), ”away” (abwesend) und dnd (do not disturb) annehmen und beschreibt den aktuellen Status des Benutzers vc dieses Flag beschreibt die Fähigkeiten eines Users zu Audio- und Videokonferenzen. ”A” steht hierbei für Audio, ”V” für Video und ”C” für Konferenzen mit mehr als einem Teilnehmer. Sollte der User keine der eben genannten Möglichkeiten bieten wird vc auf ”!” gesetzt. Listing 4.1: Beispiel aller verwendeten Records [6] meinpc . l o c a l . A 1 3 8 . 2 3 2 . 9 4 . 9 9 roland@meinpc . p r e s e n c e . t c p . l o c a l . SRV 5598 meinpc . l o c a l . p r e s e n c e . t c p . l o c a l . PTR roland@meinpc . p r e s e n c e . t c p . l o c a l . roland@meinpc . p r e s e n c e . t c p . l o c a l . IN TXT ” t x t v e r s =1” ” 1 s t=r o l a n d ” ” e m a i l=r o l a n d . matha@student . uibk . ac . a t ” ” j i d=r o l a n d @ j a b b e r . o r g ” ” l a s t= r o l i ” ”msg=s c h r e i b e g e r a d e ” ” n i c k=r o l i 8 7 ” ” p o r t . p2pj =5677” ” s t a t u s=a v a i l ” ” vc =!” Das oben gezeigte Beispiel (siehe Listing 4.1) veranschaulicht die verschiedenen Recordtypen nochmals anhand von Beispielwerten. Dabei beschreibt ”meinpc” den Rechnernamen und ”roland” den gewählten Chatnamen. Aus diesem Beispiel ist ersichtlich, warum der Port des Users stets vom SRV-Record (5598) genommen werden sollte und nicht vom TXTRecord (5677), weil der im TXTRecord enthaltene Port gefälscht sein kann. 12 4.2 Bestehende Ansätze 4.1.3. Nachrichtenaustausch Der Nachrichtenaustausch ist stark an den von XMPP angelehnt. Damit eine Nachricht gesendet bzw. empfangen werden kann, muss zwischen beiden Chatclients eine TCP-Verbindung bestehen. Die dazu notwendigen Informationen, wie Hostname und Port, werden dabei durch einen Service-Lookup vom Typ ” presence. tcp” erhalten. Besteht eine TCP-Verbindung muss der XML-Stream vom Aufrufer der Verbindung gestartet werden. Der Aufrufer startet einen neuen Stream mit folgenden Stream-Header: <s t r e a m : s t r e a m xmlns= ’ j a b b e r : c l i e n t ’ x m l n s : s t r e a m= ’ h t t p : // e t h e r x . j a b b e r . o r g / s t r e a m s ’> Der Empfänger antwortet daraufhin mit einem Respons der Form: <s t r e a m : s t r e a m xmlns= ’ j a b b e r : c l i e n t ’ x m l n s : s t r e a m= ’ h t t p : // e t h e r x . j a b b e r . o r g / s t r e a m s ’> Somit wurde der Stream erfolgreich geöffnet und es können Nachrichten übermittelt werden. Die Nachrichten besitzen, ähnlich zu XMPP, ein ”to”-Attribut (Empfänger) und ein ”from”-Attribut (Sender). Ein Beispiel einer solchen Nachricht ist: <message t o= ’ a l i c e @ e x a m p l e ’ from= ’ heidi@example ’> <body>H i e r s t e h t d i e N a c h r i c h t</ body> </ message> Soll die TCP-Verbindung bzw. der Stream geschlossen und somit der Chat beendet werden, muss ein Stream-End-Tag übermittelt werden mit folgender Form: </ s t r e a m : s t r e a m> 4.2. Bestehende Ansätze In der SmackAPI existiert bereits eine Link-Local-Messaging Unterstützung. Allerdings befindet sich diese noch in der Entwicklung und wird frühestens in der nächsten SmackAPI Version zum Einsatz kommen. Die Klassenhierarchie innerhalb der SmackAPI ändert sich nicht, weil die Unterstützung durch Modifiezierung bereits bestehender Klassen implementiert wurde [9]. 4.3. Problemstellung Es soll eine Link-Local-Messaging Unterstützung als Eclipse-Plugin geschrieben werden, die ins ECF integriert werden kann. Die Implementierung soll dabei möglichst ECF-konform sein, d.h. bereits bestehende Interfaces bzw. Komponenten sollen verwendet werden, um die Integration ins ECF zu erleichtern. 13 4 Link-Local Messaging (XEP-174) 4.4. Verwendete Ansätze bzw. APIs Für die Implementierung wurden drei bereits bestehende Ansätze verwendet: • DNS-SD: Damit der Client im Netz sichtbar ist und Kontakte im lokalen Netz gefunden werden, wird DNS-SD von Apple verwendet • Eclipse Plugin: Für die Implementierung wurden verschiedene Eclipse Plugins, vor allem vom ECF, benötigt und das fertige Projekt wird als Plugin veröffentlicht • SAXParser: Der Nachrichtenaustausch basiert auf XMPP und somit auf XML-Streams. Damit Nachrichten richtig geparst werden wird ein SAXParser verwendet. In den folgenden Abschnitten wird auf die verwendeten Ansätze genauer eingegangen. 4.4.1. DNS-SD Um das Problem, Namen und IP-Adressen ohne DNS-Server zu übersetzen, gibt es zwei Lösungsmöglichkeiten für ein Zeroconf-Netzwerk: • JmDNS (Java Multicast DNS) • DNS-SD (DNS Service Discovery) In dieser Arbeit wird nur DNS-SD genauer betrachtet. JmDNS funktioniert analog. DNS-SD wurde von Apple entwickelt und ist im Package ”com.apple.dnssd” enthalten. Eine ausführliche Dokumentation des Packages befindet sich auf der Entwicklerhomepage von Apple2 . Die Verwendung von DNS-SD ist durch Implementierung der notwendigen Interfaces relativ einfach und übersichtlich gehalten. Ein Bespiel für die Verwendung von DNS-SD ist die, für die Arbeit geschriebene Klasse LLPresenceDiscover. Diese Klasse dient dazu den Service des Clients zu registrieren und andere Services im lokalen Netz zu suchen. Damit ein eigener Service registriert werden kann, reicht der Aufruf der statischen Methode: public s t a t i c DNSSDRegistration r e g i s t e r ( int f l a g s , int i f I n d e x , S t r i n g serviceName , S t r i n g regType , S t r i n g domain , S t r i n g host , int port , TXTRecord txtRecord , R e g i s t e r L i s t e n e r l i s t e n e r ) throws DNSSDException Der Wert des Parameters ”flags” wird zur Zeit noch ignoriert und soll erst in Zukunft unterstützt werden. ”ifIndex” beschreibt das Interface auf welchem der Service registriert werden soll. Ist ”ifIndex” gleich Null, wird der Service auf 2 http://developer.apple.com/mac/library/documentation/Java/Reference/ DNSServiceDiscovery_JavaRef/com/apple/dnssd/package-summary.html 14 4.4 Verwendete Ansätze bzw. APIs allen möglichen Interfaces registriert. Der ”serviceName” beschreibt im Falle von Link-Local-Messaging den Usernamen. ”regType” ist der Registrierungstyp, in diesem Fall immer ” presence. tcp.”. Die anderen Parameter sind selbsterklärend. Es ist weiters möglich andere Services, vom Typ ”regType”, im Netz zu suchen bzw. nach einem Service zu ”browsen”. Hierfür wird die Methode browse verwendet: public s t a t i c DNSSDService browse ( int f l a g s , int i f I n d e x , S t r i n g regType , S t r i n g domain , B r o w s e L i s t e n e r l i s t e n e r ) throws DNSSDException Da die Ausführung dieser Methode viel Netzwerk-Bandbreite benötigt sollte stets nach erfolgreicher Suche die Methode DNSSDService.stop() aufgerufen werden um das Browsen zu beenden. Damit Aktualisierungen der Services im Netz erkannt werden, muss die Klasse LLPresenceDiscover folgende drei Interfaces implementieren: RegisterListener3 Listener für die Registrierung des eigenen Services durch die Methode DNSSD.register(...) BrowseListener4 Listener für die Methode DNSSD.browse(...). Der Listener reagiert, wenn ein Service, in diesem Fall vom Typ ” presence. tcp.”, gefunden bzw. verloren wurde und kann dementsprechend reagieren. ResolveListener5 Listener für die Methode DNSSD.resolve(...). Der Listener reagiert, wenn der gesuchte Servicename aufgelöst wurde. 4.4.2. Eclipse-Plugin Plugins6 ermöglichen die einfache Erweiterung der Eclipse Entwicklunsumgebung (IDE) um weitere Funktionalitäten bzw. Komponenten. Ein Eclipse-Plugin besteht aus zwei Teilen: plugin.xml ist eine Plugin Manifest Datei und enthält die eindeutige ID, den Namen, die Version, eine Liste der notwendigen Packages und die Extension Points des Plugins, damit Eclipse das Plugin in die Registry eintragen kann und die IDE dementsprechend konfiguriert werden kann. Ein Extension Point ist eine Erweiterungsschnittstelle bereits bestehender Plugins. Es ist außerdem möglich verschiedene Eclipse-Plugins miteinander zu koppeln[2]. Quellcode die eigentliche Implementierung des Plugins. 6 http://www.eclipse.org/articles/Article-Your%20First%20Plug-in/ YourFirstPlugin.html 15 4 Link-Local Messaging (XEP-174) 4.4.3. SAXParser Ein ”Simple API for XML”-Parser, kurz SAXParser genannt, ermöglicht es XML-Daten als sequentiellen Datenstrom einzulesen und zu parsen. Der SAXParser ist ereignisorientiert und reagiert somit auf vordefinierte Ereignisse durch den Aufruf von Callback-Funktionen [3]. Ein Beispiel für einen SAXParser ist die, für diese Arbeit geschriebene Klasse SAXStreamHandler (siehe Abschnitt 4.5.2). In diesem Abschnitt wurden die verwendeten APIs aufgezählt und kurz beschrieben. Bei DNS-SD wurden, die für diese Arbeit relevanten Methoden und Interfaces genauer erläutert. Bei Eclipse-Plugin wurde vor allem auf die Bestandteile eines Plugins eingegangen. Der SAXParser wurde nur spärlich erklärt und wird im Abschnitt 4.5.2 genauer betrachtet. 4.5. Implementierung Für dieses Projekt waren eine Vielzahl an verschiedenen Klassen notwendig, damit die spätere Kompatibilität zum ECF gegeben ist. Die wichtigsten Klassen lassen sich allerdings auf drei beschränken: • BonjourRosterView • Chat • ChatManager Im folgenden werden diese drei Klassen im Detail untersucht. 4.5.1. BonjourRosterView Diese Klasse ist eine angepasste Version der bereits bestehenden Klasse RosterView (org.eclipse.ecf.ui.views.RosterView). Die Hauptaufgabe der BonjourRosterView ist es einen neuen Client im Netz zu registrieren und einen Roster bzw. eine Kontaktliste zu verwalten. Ein neuer Client wird mit der Methode public void c o n n e c t ( S t r i n g connectID ) ; registriert. Als Paramter reicht der Benutzername. Der Hostname wird automatisch gelesen und dem Benutzernamen, durch ein ”@” getrennt, angehängt um eine eindeutige ChatID zu bilden. LLPresenceDiscover Damit BonjourRosterView stets auf dem aktuellen Stand ist, ist ein Listener notwendig. Dafür wurde die innere Klasse LLPresenceDiscover eingeführt. LLPresenceDiscover implementiert, wie bereits in Abschnitt über DNS-SD erwähnt, drei Interfaces des DNS-SD (siehe Abschnitt 4.4.1). 16 4.5 Implementierung BonjourRosterGroup und BonjourRosterEntry Der Inhalt des Rosters ist in Gruppen vom Typ BonjourRosterGroup eingeteilt. Eine BonjourRosterGroup hat in sich eine Liste von Rostereinträgen des Typs BonjourRosterEntry. Diese Liste ist als ”private” deklariert und kann durch Funktionen bearbeitet werden. Die vier wichtigsten Funktionen sind: // Fuegt e i n e n neuen R o s t e r e i n t r a g i n d i e L i s t e e i n public void add ( Bonjou rRosterE ntry e n t r y ) ; // Holt e i n e n R o s t e r e i n t r a g aus d e r L i s t e public Bonjo urRoste rEntry g e t B o n j o u r R o s t e r E n t r y ( BonjourID i d ) ; // Löscht e i n e n R o s t e r e i n t r a g aus d e r L i s t e public void remove ( BonjourID i d ) ; // Holt e i n e n R o s t e r e i n t r a g aus d e r L i s t e mit dem Benutzernamen username . Wird vor a l l e m b e i d e r D o p p e l k l i c k − Funktion i n d e r BonjourRosterView verwendet . Bonjo urRoste rEntry getEntryFor ( S t r i n g username ) ; 4.5.2. Chat Die Klasse Chat verwaltet den XML-Stream über den der Chat läuft. Die Aufgabe von Chat ist es einen Stream zu starten bzw. zu schließen und Nachrichten zu senden bzw. zu empfangen. Interface IChat Die Klasse Chat implementiert das, vom ECF verwendete, Interface IChat7 .Das Interface IChat befindet sich im Package ”org.eclipse.ecf.presence.im” und definiert Funktionen zum Senden von Nachrichten. Die für diese Arbeit interessanten Funktionen sind: // L i e f e r t d i e ID d e s N a c h r i c h t e n e m p f ä n g e r s z u r u e c k ID g e t R e c e i v e r I D ( ) ; // Sendet e i n e N a c h r i c h t mit dem Body messageBody an den Nachrichtenempfaenger void sendChatMessage ( S t r i n g messageBody ) throws ECFException ; SAXStreamHandler Als Listener für den Inputstream und als SAXParser wurde die innere Klasse SAXStreamHandler eingeführt. Die Aufgabe von SAXStreamHandler ist es die empfangenen XML-Daten des Chatstreams auszulesen und Nachrichten heraus zu filtern. Für die Auswertung wurde die Klasse SAXStreamHandler von der 7 http://www.eclipse.org/ecf/org.eclipse.ecf.docs/api/org/eclipse/ecf/presence/ im/IChat.html 17 4 Link-Local Messaging (XEP-174) Klasse DefaultHandler8 abgeleitet und es wurden folgende Callback-Funktionen überladen: // Das Ende d e s Dokuments wurde e r r e i c h t public void endDocument ( ) throws SAXException ; // Ein XML−S t a r t −Tag wurde e r r e i c h t . Die Bezeichnung d e s Tags s t e h t d a b e i i n qName , A t t r i b u t e i n a t t r i b u t e s public void s t a r t E l e m e n t ( S t r i n g u r i , S t r i n g localName , S t r i n g qName , A t t r i b u t e s a t t r i b u t e s ) throws SAXException ; // Ein XML−End−Tag wurde e r r e i c h t . Die Bezeichnung d e s Tags s t e h t d a b e i i n qName public void endElement ( S t r i n g u r i , S t r i n g localName , S t r i n g qName) throws SAXException ; // Eine Z e i c h e n k e t t e wurde e r r e i c h t . Vor a l l e m zum A u s l e s e n d e r Chatmessage verwendet public void c h a r a c t e r s ( char ch [ ] , int s t a r t , int l e n g t h ) throws SAXException ; Bei der Methode ”startElement” wurden ”STREAM:STREAM”-, ”BODY”und ”HTML”-Start-Tags berücksigt. Bei einem ”STREAM:STREAM”-Tag wird ein neuer Chat gestartet. Nach einem ”Body”-Tag kommt die Textnachricht. Um eine doppelte Ausgabe der Textnachricht zu vermeiden muss das Vorhandensein des ”HTML”-Tags geprüft werden, denn im ”HTML”-Tag können Eigenschaften, wie etwa Schriftgröße oder Schriftfarbe, angegeben werden und enthält nochmals ein ”Body”-Tag mit der Chatnachricht. Bei der Methode ”endElement” wurde das ”STREAM:STREAM”-End-Tag berücksigt, damit auf eine Beendigung des Streams, von der Gegenseite ausgehend, reagiert werden kann. 4.5.3. ChatManager Die Klasse ChatManager verwaltet Objekte vom Typ Chat. Die Aufgabe von Chatmanager ist es, Nachrichten an den richtigen Chat weiter zu senden und bei einem eingehenden Stream einen neuen Chat zu starten. Interface IChatMessageSender Damit die Klasse ChatManager Nachrichten ECF-kompatibel sendet, wird das interface IChatMessageSender9 implementiert. Das Interface IChatMessageSender befindet sich im Package ”org.eclipse.ecf.presence.im” und definiert zwei Funktionen zum Senden von Nachrichten: // Für d i e Implementierung i s t d i e s e Methode n i c h t r e l e v a n t void sendChatMessage ( ID toID , ID threadID , 8 http://www.aip.de/~granzer/javadoc/jaxp/org/xml/sax/helpers/DefaultHandler. html 9 http://www.eclipse.org/ecf/org.eclipse.ecf.docs/api/org/eclipse/ecf/presence/ im/IChatMessageSender.html 18 4.6 Zusammenfassung IChatMessage . Type type , S t r i n g s u b j e c t , S t r i n g body , Map p r o p e r t i e s ) throws ECFException // Nur d i e s e Methode i s t a u s i m p l e m e n t i e r t // toID − d e r Empfänger d e r N a c h r i c h t // body − d i e N a c h r i c h t void sendChatMessage ( ID toID , S t r i n g body ) throws ECFException Für das Senden von Nachrichten durch die Klasse ChatManager, ist nur die zweite Methode brauchbar. Durch den Parameter ”toID” kann ChatManager den richtigen Chat in der internen Chat-Liste finden und die Nachricht ”body” senden. SockConListener Die Klasse ChatManager ist, neben der Aufgabe einen Chat zu starten und Nachrichten zu senden, weiters in der Lage auf eingehende Chatverbindungen zu reagieren. Dazu wird die innere Klasse SockConListener verwendet. SockConListener ist von der Klasse Thread abgeleitet und erfüllt die Aufgabe eines Servers, der auf einem bestimmten Port lauscht. Der Port ist standardmäßig auf den Wert ”DEFAULT SERVER PORT”(=5299) gesetzt. Bei einem eingehenden Socket öffnet SockConListener einen neuen Chat und fügt diesen in die Chat-Liste des ChatManagers ein. In diesem Abschnitt wurden die drei wichtigsten Klassen des Projekts aufgezählt und beschrieben. Es wird jeweils auf die Verwendung der Klasse und deren Aufbau (innere Klassen) eingegangen. Bei der Verwendung der Klasse werden vor allem die bereitgestellten Methoden genauer erläutert. 4.6. Zusammenfassung In diesem Kapitel wurde der Begriff Link-Local-Messaging erklärt, dessen Funktionweise beschrieben und bereits bestehende Ansätze analysiert. Weiters wurde eine neue Link-Local-Messaging Implementation vorgestellt. Die hier vorgestellte Implementation wurde bereits veröffentlicht und an das ECF Projekt zur Integration übergeben. Wahrscheinlich ist die Implementation bereits in der nächsten ECF Version verfügbar. 19 5. Zusammenfassung und Ausblick Das Thema XMPP zieht sich als roter Faden durch die Arbeit. Zu Beginn wurde eine Begriffdefinition für XMPP angegeben und die grundlegende Kommunikation erklärt. Es wurden die, für die Kommunikation wichitgen, Begriffe Jabber-ID, XML-Stream und XML-Stanza eingeführt und anhand von Beispielen anschaulich erklärt. Zusätzlich wurden bereits bestehende Ansätze für Java aufgezählt, wobei das Augenmerk auf die SmackAPI gerichtet wurde, weil diese im ECF verwendet wird. Im dritten Kapitel wurde auf das ECF Projekt, die SmackAPI und vor allem auf die Integration der neuen SmackAPI (3.1) ins ECF eingegangen. Es wurden die wichtigsten Neuerungen der SmackAPI Version 3.1 aufgelistet und die verschiedenen Schritte der Integration ins ECF beschrieben. Dabei wurden Probleme, wie etwa Lizenzprobleme ersichtlich. Das in Kapitel 4 beschriebene Link-Local Messaging baut auf XMPP und Zeroconf auf. Link-Local verwendet dabei für die Service Discovery die Zeroconf Technik. Für den eigentlichen Nachrichtenaustausch wird eine stark vereinfachte Abwandlung von XMPP benützt. Weiters wurden bereits bestehende bzw. verwendete Ansätze aufgezeigt und beschrieben, sowie eine neue Link-Local Messaging Implementation vorgestellt. Die neue Implementation wurde bereits veröffentlicht und an das ECF Projekt zur Integration übergeben. Wahrscheinlich ist die Implementation bereits in der nächsten ECF Version verfügbar. Im folgenden werden drei Erweiterungsvorschläge für die Implementation und je eine kurze Anleitung für deren Umsetzung gegeben. 5.1. Vorschläge zur Erweiterung Für die Implementation der Link-Local Messaging Unterstützung gibt es drei Erweiterungsvorschläge: • FileTransfer: Der Nachrichtenaustausch unter den Clients kann durch den Dateienaustausch erweitert werden. Dazu muss die Klasse Chat für den ausgehenden Transfer und die Klasse SAXStreamHandler für den eingehenden Filetransfer modifiziert werden. • Statusanzeige: Bisher wird der, im TXTRecord angegebene Status nicht berücksigt, d.h. ”unsichtbare” Clients werden trotzdem in der BonjourRosterView angezeigt. Des weiteren könnte im TXTRecord, wie vorgesehen, eine Statusnachricht bei Abwesendheit in der BonjourRosterView aufscheinen. 20 5.1 Vorschläge zur Erweiterung • Messagetypingnotification: Die im Interface IChat definierte Methode sendTypingMessage(...) könnte in der Klasse Chat ausimplementiert werden, damit der Client sieht, ob der Gesprächspartner gerade eine Nachricht schreibt. 21 Literaturverzeichnis [1] Xmpp software: Libraries. Website, 1999-2009. Available online at http: //xmpp.org/software/libraries.shtml; visited on December 29th 2009. [2] Heiko Seeberger Manfred Hennig. Einfà 14 hrung in den extension point-mechanismus von eclipse. Website, 2008. Available online at http://www.sigs.de/publications/js/2008/01/hennig_ seeberger_JS_01_08.pdf; visited on January 09th 2010. [3] David Megginson. Sax. Website, 2001. Available online at http://www. saxproject.org/; visited on January 10th 2010. [4] Jin Li Nick Edgar, Kevin Haaland and Kimberley Peter. Eclipse user interface guidelines. Website, 2004. Available online at http://www.eclipse. org/articles/Article-UI-Guidelines/Contents.html; visited on December 31th 2009. [5] Remko Troncon Peter Saint-Andre, Kevin Smith. XMPP: The Definitive Guide: Building Real-Time Applications with Jabber Technologies. O’Reilly Media, 2009. [6] Peter Saint-Andre. Xep-0174: Serverless messaging. Website, 1999-2009. Available online at http://xmpp.org/extensions/xep-0174.html; visited on December 31th 2009. [7] Peter Saint-Andre. Extensible messaging and presence protocol (xmpp): Core. Website, 2004. Available online at http://xmpp.org/rfcs/ rfc3920.html; visited on December 29th 2009. [8] Jive Software. Smackapi. Website. Available online at http://www. igniterealtime.org/projects/smack/; visited on January 01th 2010. [9] Jive Software. Xep-0174 (link-local) support in smack. Website, 2009. Available online at http://www.igniterealtime.org/issues/browse/ SMACK-262; visited on January 09th 2010. [10] Wikipedia. Extensible messaging and presence protocol. Website, 2009. Available online at http://de.wikipedia.org/wiki/Extensible_ Messaging_and_Presence_Protocol; visited on December 26th 2009. 22 A. Anhang A.1. Aufbau des Eclipse Workbench Abbildung A.1.: Aufbau des Eclipse Workbench [4] 23