1 / 33

Implementierung eines IRC Servers in Java

This project implements an IRC server in Java, allowing users to connect, join channels, and chat with other users in the network. It follows the IRC protocol standards specified in RFCs.

grindstaff
Download Presentation

Implementierung eines IRC Servers in Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Implementierung eines IRC Servers in Java von M. Serhat Cinar AI 11030409 WPF Compiler & Interpreter SS04 bei Prof. Dr. Ehses

  2. IRC IRC := Internet Relay Chat (Relay = Relais, Übertragung) Der Benutzer meldet sich bei einem Server (z.B. A) an. Dieser Server wiederum ist mit anderen Servern desselben Netzes verbunden (z.B. mit Server C über Server B). Jeder Benutzer, der mit einem Server verbunden ist erhält vom Server eine Liste aller Channels, die in dem jeweiligen Netz verfügbar sind und kann sich in jedem beliebigen Channel anmelden (JOIN). Das IRC-Geflecht von Servern ist in Netze aufgeteilt. Beispiele für verschiedene große Netze sind das DALnet, Efnet oder IRCnet. Benutzer im selben Channel können sich unterhalten (chatten). Schickt Benutzer A über Server A eine Nachricht an Benutzer C an Server C, so wird die Nachricht wie ein PING über das IRC-Netz geschickt. Die verschiedenen Stationen bei einer solchen Weiterleitung nennt man Relais. Das Prinzip ist dem DNS, Mail-Relay oder dem PING Protokoll ähnlich.

  3. IRC als Netzwerk

  4. IRC - Standard Die Standards für das IRC-Protokoll werden in den Request for Comments (RFC‘s) verwaltet. RFC 1459 - IRC Protocol RFC 2810 - IRC Architecture RFC 2811 - IRC Channel Management RFC 2812 - IRC Client Protocol RFC 2813 - IRC Server Protocol

  5. RFC 2812 Internet Relay Chat: Client Protocol 1/2 message = [ ":" prefix SPACE ] command [ params ] crlf prefix = servername / ( nickname [ [ "!" user ] "@" host ] ) command = 1*letter / 3digit params = *14( SPACE middle ) [ SPACE ":" trailing ] =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ] nospcrlfcl = %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B-FF ; any octet except NUL, CR, LF, " " and ":" middle = nospcrlfcl *( ":" / nospcrlfcl ) trailing = *( ":" / " " / nospcrlfcl ) SPACE = %x20 ; space character crlf = %x0D %x0A ; "carriage return" "linefeed" letter = %x41-5A / %x61-7A ; A-Z / a-z digit = %x30-39 ; 0-9 hexdigit = digit / "A" / "B" / "C" / "D" / "E" / "F" special = %x5B-60 / %x7B-7D ; "[", "]", "\", "`", "_", "^", "{", "|", "}„ user = 1*( %x01-09 / %x0B-0C / %x0E-1F / %x21-3F / %x41-FF ) ; any octet except NUL, CR, LF, " " and "@"

  6. RFC 2812 Internet Relay Chat: Client Protocol 2/2 key = 1*23( %x01-05 / %x07-08 / %x0C / %x0E-1F / %x21-7F ) ; any 7-bit US_ASCII character, ; except NUL, CR, LF, FF, h/v TABs, and " " servername = hostname host = hostname / hostaddr hostname = shortname *( "." shortname ) shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit ) ; as specified in RFC 1123 [HNAME] hostaddr = ip4addr / ip6addr ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit ip6addr = 1*hexdigit 7( ":" 1*hexdigit ) ip6addr =/ "0:0:0:0:0:" ( "0" / "FFFF" ) ":" ip4addr nickname = ( letter / special ) *8( letter / digit / special / "-" )

  7. Message Grundstruktur Message :Prefix Command Paramlist Server / User SPACE Param * :Trailing

  8. Verschiedene Implementierungen: CRLF vs. LF RFC 2812: message = [ ":" prefix SPACE ] command [ params ] crlf crlf = %x0D %x0A mIRC: 4E 49 43 4B 20 74 65 73 74 0A NICK test. BitchX: 4E 49 43 4B 20 74 65 73 74 0D 0A NICK test..

  9. jIrcSX.flex 1/2 CR = \x0D LF = \x0A CRLF = {CR} {LF} SPACE = \x20 DIGIT = \x30|\x31|\x32|\x33|\x34|\x35|\x36|\x37|\x38|\x39 LETTER_HEX = "A" | "B" | "C" | "D" | "E" | "F" LETTER = [A-Za-z] COLON = ":" AT = "@" EXCLAMATION_MARK = "!" DOT = "." VALUE = "#" COMMA = "," PLUS = "+" MINUS = "-" AND = "&"

  10. jIrcSX.flex 2/2 UNDERSCORE = "_" ACCENT_CIRCONFLEX = "^" SQUARED_BRACKET_LEFT = "[" SQUARED_BRACKET_RIGHT = "]" BRACE_LEFT = "{" BRACE_RIGHT = "}" BACKSLASH = "\\" APOSTROPHE = "`" OR = "|" TAB = \x09 NULL = \x00 BELL = \x07 FF = \x0C SYMBOL_OTHER = . HEXDIGIT = {DIGIT} | {LETTER_HEX} IP6ADDR = ( {HEXDIGIT}+ (":" {HEXDIGIT}+){7} ) | ( "0:0:0:0:0:" ("0"|"FFFF") ":" {IP4ADDR} ) IP4ADDR = {DIGIT} {1,3} "." {DIGIT} {1,3} "." {DIGIT} {1,3} "." {DIGIT} {1,3} HOSTNAME = {SHORTNAME} ( "." {SHORTNAME})+ SHORTNAME = ( {LETTER} | {DIGIT} ) ( {LETTER} | {DIGIT} | "-" )* ( {LETTER} | {DIGIT} )*

  11. Recursive Descending Parser private int lookahead(), private void match(int symbol), private void match() public INode parse(String pIrcMessage) private INode message() private INode prefix() private String nickname() private String letterOrSpecial() private String letterOrSpecialOrDigitOrMinusOrEmpty() private String user() private String userLetterOrEmpty() private INode host() private INode hostaddr() private INode command() private INode params() private String middle() private String middleRepeatOrEmpty() private String trailing()

  12. MessageNode public class MessageNode implements INode { public INode mPrefix, mCommand, mParams; public void accept(IVisitor v)[...] public String getCommand(){ return ((CommandNode) mCommand).mCommand; } public boolean hasColonedTrailing(){ if (mParams==null) return false; return ((ParamsNode) mParams).mColonedTrailing; } public int getParamsSize(){ if (mParams==null) return 0; return ((ParamsNode) mParams).mMiddles.size(); } public String getParam(int i){ if (mParams==null) return null; ParamsNode lPN = (ParamsNode) mParams; if (lPN.mMiddles == null || lPN.mMiddles.size()<=i) return null; return ((String)lPN.mMiddles.get(i)); } }

  13. Weitere Nodes 1/2 public class PrefixHostNameNode implements INode { public String mServerName; [...] } public class CommandNode implements INode { public String mCommand; [...] } public class PrefixNickUserHostNode implements INode { public String mNickName, mUser; public INode mHost; [...] }

  14. Weitere Nodes 2/2 public class IPv4AdressNode implements INode { public String mAdress; [...] } public class ParamsNode implements INode { public Vector mMiddles; public boolean mColonedTrailing = false; }

  15. Verbindungsaufbau Client->Server 1/2 The commands described here are used to register a connection with an IRC server as a user as well as to correctly disconnect. A "PASS" command is not required for a client connection to be registered, but it MUST precede the latter of the NICK/USER combination (for a user connection) or the SERVICE command (for a service connection). The RECOMMENDED order for a client to register is as follows: 1. Pass message 2. Nick message 2. Service message 3. User message Upon success, the client will receive an RPL_WELCOME (for users) or RPL_YOURESERVICE (for services) message indicating that the connection is now registered and known the to the entire IRC network. The reply message MUST contain the full client identifier upon which it was registered.

  16. Verbindungsaufbau Client->Server 2/2 NICK test USER test "" "irc.gamesnet.net" :x :genesis.GamesNET.net NOTICE AUTH :Looking up the hostname for 81.173.149.151... :genesis.GamesNET.net NOTICE AUTH :Please wait while your system is scanned for insecure proxy servers... :genesis.GamesNET.net NOTICE AUTH :Successfully resolved your IP to xdsl-81-173-149-151.netcologne.de. PING :4048004E PING :4048004E PONG :4048004E PONG :4048004E :genesis.GamesNET.net 001 test :Welcome to the Internet Relay Chat network, test!~test@xdsl-81-173-149-151.netcologne.de = Client = Server

  17. NICK Message Command: NICK Parameters: <nickname> NICK command is used to give user a nickname or change the existing one. Numeric Replies: ERR_NONICKNAMEGIVEN ERR_ERRONEUSNICKNAME ERR_NICKNAMEINUSE ERR_NICKCOLLISION ERR_UNAVAILRESOURCE ERR_RESTRICTED Examples: NICK Wiz ; Introducing new nick "Wiz" if session is still unregistered, or user changing his nickname to "Wiz" :WiZ!jto@tolsun.oulu.fi NICK Kilroy ;Server telling that WiZ changed his nickname to Kilroy.

  18. Weitere Befehle 1/3 3.1 Connection Registration 3.1.1 Password message 3.1.2 Nick message 3.1.3 User message 3.1.4 Oper message 3.1.5 User mode message 3.1.6 Service message 3.1.7 Quit 3.1.8 Squit 3.2 Channel operations 3.2.1 Join message 3.2.2 Part message 3.2.3 Channel mode message 3.2.4 Topic message 3.2.5 Names message 3.2.6 List message 3.2.7 Invite message 3.2.8 Kick command

  19. Weitere Befehle 2/3 3.3 Sending messages 3.3.1 Private messages 3.3.2 Notice 3.4 Server queries and commands 3.4.1 Motd message 3.4.2 Lusers message 3.4.3 Version message 3.4.4 Stats message 3.4.5 Links message 3.4.6 Time message 3.4.7 Connect message 3.4.8 Trace message 3.4.9 Admin command 3.4.10 Info command 3.5 Service Query and Commands 3.5.1 Servlist message 3.5.2 Squery

  20. Weitere Befehle 3/3 3.6 User based queries 3.6.1 Who query 3.6.2 Whois query 3.6.3 Whowas 3.7 Miscellaneous messages 3.7.1 Kill message 3.7.2 Ping message 3.7.3 Pong message 3.7.4 Error 4. Optional features 4.1 Away 4.2 Rehash message 4.3 Die message 4.4 Restart message 4.5 Summon message 4.6 Users 4.7 Operwall message 4.8 Userhost message 4.9 Ison message

  21. Software Architektur UserList 1 . 1 1 * Server 1 * ClientHandler 1 1 User 1 1 1 1 1 44.. RDParser RegistrationProcessor CommandProcessor

  22. User Die Klasse User verwaltet userbezogene Informationen. publicclassUser{ publicStringmNick; publicClientHandlermClientHandler; publicStringmPass; publicStringmUsername; publicStringmHostname; publicStringmRealname; publicStringmMode; publicMessageNodemLastMessage; publicStringmInternetAdress; }

  23. Server Der Server erzeugt einen ServerSocket auf dem IRC Port 6667. Für jede ankommende Verbindung wird ein eigener ClientHandler erzeugt. while (mRunning){ new ClientHandler(lServerSocket.accept(), this); } Weiterhin stellt der Server Zentrale Informationen zur Verfügung, wie die Liste der aktuell verbundenen Clients. public String getName() public String getServerAdress() public String getServerAdressString() publicint getServerPort() public UserList getUserList()

  24. ClientHandler 1/3 Jeder Client erhält einen eigenen ClientHandler, der als nebenläufiger Prozess alle Eingabezeichen des Clients aus dem InputStream des Sockets liest, bis das Ende einer Message erreicht wird und anschließend parst. publicsynchronized MessageNode getNextMessageNode() throws SyntaxException, IOException{ StringBuffer lInputBuffer = new StringBuffer(); int lReadByte; while ( (lReadByte = mInputReader.read()) != -1){ lInputBuffer.append((char)lReadByte); if (lInputBuffer.indexOf(LexicalSymbols.STRING_LF)>-1) break; } if (lReadByte==-1) mUser.mLastMessage = null; else mUser.mLastMessage = (MessageNode) mServer.parse(lInputBuffer.toString()); return mUser.mLastMessage; }

  25. ClientHandler 2/3 Weitere Methoden ermöglichen das Senden von Nachrichten über den OutputSteam: public synchronized void sendMessage(String pMessage){ Log.getInstance().writeln(toString()+" sending: "+pMessage); mPrintWriter.print(pMessage+LexicalSymbols.STRING_CRLF); mPrintWriter.flush(); } public synchronized void sendNumericReply(String [] pNumber){ sendMessage(NumericReplies.getNumericReplyMessage(pNumber, mUser)); }

  26. ClientHandler 3/3 try { RegistrationProcessor lRegistration = new RegistrationProcessor(); lRegistration.process(mUser, null); while (mRunning){ // read next message from client try { lMessage = getNextMessageNode(); if (lMessage==null)mRunning = false; if (mCommandProcessors.containsKey(lMessage.getCommand().toUpperCase())){ lCommandProcessor = (ICommandProcessor) mCommandProcessors.get(lMessage.getCommand().toUpperCase()); lCommandProcessor.process(mUser, lMessage); } } catch (SyntaxException e) { Log.getInstance().writeln("ParseException: "+e.toString()); sendNumericReply(NumericReplies.ERR_NEEDMOREPARAMS); }

  27. ICommandProcessor public interface ICommandProcessor { public void process(User pUser, MessageNode pMessageNode) throws IOException; public String getCommandString(); }

  28. NickProcessor public void process(User pUser, MessageNode pMessageNode) throws IOException { String lNewNick = pMessageNode.getParam(0); if (lNewNick != null){ UserList lList = pUser.mClientHandler.getServer().getUserList(); lList.renameUser(pUser, lNewNick); // TODO broadcast new nick of user } else pUser.mClientHandler. sendNumericReply( NumericReplies.ERR_NONICKNAMEGIVEN); } public String getCommandString() { return CommandStrings.NICK; }

  29. PingProcessor public void process(User pUser, MessageNode pMessageNode) throws IOException { // PING :4048004E // PONG :4048004E String lPingCode = pMessageNode.getParam(0); if (lPingCode != null) pUser.mClientHandler.sendMessage("PONG :"+lPingCode); else pUser.mClientHandler.sendMessage("PONG"); } public String getCommandString() { return CommandStrings.PING; }

  30. Auszug einer Login-Prozedur 1/2 Client connected: 127.0.0.1 ClientHandler 127.0.0.1 received: "NICK test" COMMAND: NICK MIDDLE: test ClientHandler test received: "USER test "" "127.0.0.1" :x" COMMAND: USER MIDDLE: test MIDDLE: "" MIDDLE: "127.0.0.1" ClientHandler test sending: :127.0.0.1 001 test :Welcome to the Internet Relay Network test!test@127.0.0.1 ClientHandler test sending: :127.0.0.1 002 test :Your host is 127.0.0.1 [127.0.0.1:6667], running version jIRC Server X Version 25.06.2004 ClientHandler test sending: :127.0.0.1 003 test :This server was created <date>

  31. Auszug einer Login-Prozedur 2/2 ClientHandler test sending: :127.0.0.1 004 test :127.0.0.1 [127.0.0.1:6667] <version> <available user modes> <available channel modes> ClientHandler test sending: :127.0.0.1 005 test :Try server 127.0.0.1, port <port number> ClientHandler test sending: :127.0.0.1 251 test :There are <integer> users and <integer> services on <integer> servers ClientHandler test sending: :127.0.0.1 252 test <integer> :operator(s) online ClientHandler test sending: :127.0.0.1 253 test <integer> :unknown connection(s) ClientHandler test sending: :127.0.0.1 254 test <integer> :channels formed ClientHandler test sending: :127.0.0.1 255 test :I have <integer> clients and <integer> servers ClientHandler test sending: :127.0.0.1 375 test :- <server> Message of the day - ClientHandler test sending: :127.0.0.1 372 test :- <text> ClientHandler test sending: :127.0.0.1 376 test :End of MOTD command

  32. TODO • Weitere IRC Befehle über die Schnittstelle ICommandProcessor implementieren • Channel Verwaltung • Server to Server Kommunikation

  33. Referenzen jIrcSX – www.graviton.de/ai/c-und-i Der in diesem Projekt entstehende IRC-Server BitchX – www.bitchx.org DOS IRC Client für Unix/Linux/MacOS/Windows mIRC - www.mirc.com IRC Client mit GUI für Windows RFC Archiv - www.faqs.org/rfcs jFlex – jflex.de Java Scanner Generator

More Related