Implementierung eines IRC Servers in Java von M

  • Slides: 33
Download presentation
Implementierung eines IRC Servers in Java von M. Serhat Cinar AI 11030409 WPF Compiler

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

IRC : = Internet Relay Chat (Relay = Relais, Übertragung) Der Benutzer meldet sich

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. 2

IRC als Netzwerk 3

IRC als Netzwerk 3

IRC - Standard Die Standards für das IRC-Protokoll werden in den Request for Comments

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 4

RFC 2812 Internet Relay Chat: Client Protocol 1/2 message prefix command params = =

RFC 2812 Internet Relay Chat: Client Protocol 1/2 message prefix command params = = =/ nospcrlfcl = middle trailing = = SPACE crlf letter digit hexdigit special = = = user = [ ": " prefix SPACE ] command [ params ] crlf servername / ( nickname [ [ "!" user ] "@" host ] ) 1*letter / 3 digit *14( SPACE middle ) [ SPACE ": " trailing ] 14( SPACE middle ) [ SPACE [ ": " ] trailing ] %x 01 -09 / %x 0 B-0 C / %x 0 E-1 F / %x 21 -39 / %x 3 B-FF ; any octet except NUL, CR, LF, " " and ": " nospcrlfcl *( ": " / nospcrlfcl ) *( ": " / " " / nospcrlfcl ) %x 20 ; space character %x 0 D %x 0 A ; "carriage return" "linefeed" %x 41 -5 A / %x 61 -7 A ; A-Z / a-z %x 30 -39 ; 0 -9 digit / "A" / "B" / "C" / "D" / "E" / "F" %x 5 B-60 / %x 7 B-7 D ; "[", "]", "", "`", "_", "^", "{", "|", "}„ 1*( %x 01 -09 / %x 0 B-0 C / %x 0 E-1 F / %x 21 -3 F / %x 41 -FF ) ; any octet except NUL, CR, LF, " " and "@" 5

RFC 2812 Internet Relay Chat: Client Protocol 2/2 key = servername hostname shortname =

RFC 2812 Internet Relay Chat: Client Protocol 2/2 key = servername hostname shortname = = hostaddr ip 4 addr ip 6 addr nickname 1*23( %x 01 -05 / %x 07 -08 / %x 0 C / %x 0 E-1 F / %x 21 -7 F ) ; any 7 -bit US_ASCII character, ; except NUL, CR, LF, FF, h/v TABs, and " " hostname / hostaddr shortname *( ". " shortname ) ( letter / digit ) *( letter / digit / "-" ) *( letter / digit ) ; as specified in RFC 1123 [HNAME] = ip 4 addr / ip 6 addr = 1*3 digit ". " 1*3 digit = 1*hexdigit 7( ": " 1*hexdigit ) =/ "0: 0: 0: " ( "0" / "FFFF" ) ": " ip 4 addr = ( letter / special ) *8( letter / digit / special / "-" ) 6

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

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

Verschiedene Implementierungen: CRLF vs. LF RFC 2812: message = [ ": " prefix SPACE

Verschiedene Implementierungen: CRLF vs. LF RFC 2812: message = [ ": " prefix SPACE ] command [ params ] crlf = %x 0 D %x 0 A m. IRC: 4 E 49 43 4 B 20 74 65 73 74 0 A NICK test. Bitch. X: 4 E 49 43 4 B 20 74 65 73 74 0 D 0 A NICK test. . 8

j. Irc. SX. flex 1/2 CR = x 0 D LF = x 0

j. Irc. SX. flex 1/2 CR = x 0 D LF = x 0 A CRLF = {CR} {LF} SPACE = x 20 DIGIT = x 30|x 31|x 32|x 33|x 34|x 35|x 36|x 37|x 38|x 39 LETTER_HEX = "A" | "B" | "C" | "D" | "E" | "F" LETTER = [A-Za-z] COLON = ": " AT = "@" EXCLAMATION_MARK = "!" DOT = ". " VALUE = "#" COMMA = ", " PLUS = "+" MINUS = "-" AND = "&" 9

j. Irc. SX. flex 2/2 UNDERSCORE = "_" ACCENT_CIRCONFLEX = "^" SQUARED_BRACKET_LEFT = "["

j. Irc. SX. flex 2/2 UNDERSCORE = "_" ACCENT_CIRCONFLEX = "^" SQUARED_BRACKET_LEFT = "[" SQUARED_BRACKET_RIGHT = "]" BRACE_LEFT = "{" BRACE_RIGHT = "}" BACKSLASH = "\" APOSTROPHE = "`" OR = "|" TAB = x 09 NULL = x 00 BELL = x 07 FF = x 0 C SYMBOL_OTHER =. HEXDIGIT = {DIGIT} | {LETTER_HEX} IP 6 ADDR = ( {HEXDIGIT}+ (": " {HEXDIGIT}+){7} ) | ( "0: 0: 0: " ("0"|"FFFF") ": " {IP 4 ADDR} ) IP 4 ADDR = {DIGIT} {1, 3} ". " {DIGIT} {1, 3} HOSTNAME = {SHORTNAME} ( ". " {SHORTNAME})+ SHORTNAME = ( {LETTER} | {DIGIT} ) ( {LETTER} | {DIGIT} | ( {LETTER} | {DIGIT} )* "-" )* 10

Recursive Descending Parser private int lookahead(), private void match(int symbol), private void match() public

Recursive Descending Parser private int lookahead(), private void match(int symbol), private void match() public INode parse(String p. Irc. Message) private INode message() private INode prefix() private String nickname() private String letter. Or. Special. Or. Digit. Or. Minus. Or. Empty() private String user. Letter. Or. Empty() private INode hostaddr() private INode command() private INode params() private String middle. Repeat. Or. Empty() private String trailing() 11

Message. Node public class Message. Node implements INode { public INode m. Prefix, m.

Message. Node public class Message. Node implements INode { public INode m. Prefix, m. Command, m. Params; public void accept(IVisitor v)[. . . ] public String get. Command(){ return ((Command. Node) m. Command). m. Command; } public boolean has. Coloned. Trailing(){ if (m. Params==null) return false; return ((Params. Node) m. Params). m. Coloned. Trailing; } public int get. Params. Size(){ if (m. Params==null) return 0; return ((Params. Node) m. Params). m. Middles. size(); } public String get. Param(int i){ if (m. Params==null) return null; Params. Node l. PN = (Params. Node) m. Params; if (l. PN. m. Middles == null || l. PN. m. Middles. size()<=i) return null; return ((String)l. PN. m. Middles. get(i)); } } 12

Weitere Nodes 1/2 public class Prefix. Host. Name. Node implements INode { public String

Weitere Nodes 1/2 public class Prefix. Host. Name. Node implements INode { public String m. Server. Name; [. . . ] } public class Command. Node implements INode { public String m. Command; [. . . ] } public class Prefix. Nick. User. Host. Node implements INode { public String m. Nick. Name, m. User; public INode m. Host; [. . . ] } 13

Weitere Nodes 2/2 public class IPv 4 Adress. Node implements INode { public String

Weitere Nodes 2/2 public class IPv 4 Adress. Node implements INode { public String m. Adress; [. . . ] } public class Params. Node implements INode { public Vector m. Middles; public boolean m. Coloned. Trailing = false; } 14

Verbindungsaufbau Client->Server 1/2 The commands described here are used to register a connection with

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. 15

Verbindungsaufbau Client->Server 2/2 NICK test USER test "" "irc. gamesnet. net" : x :

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

NICK Message Command: NICK Parameters: <nickname> NICK command is used to give user a

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_NICKNAMEINUSE ERR_UNAVAILRESOURCE Examples: NICK Wiz changing ERR_ERRONEUSNICKNAME ERR_NICKCOLLISION ERR_RESTRICTED ; Introducing new nick "Wiz" if session is still unregistered, or user his nickname to "Wiz" : Wi. Z!jto@tolsun. oulu. fi NICK Kilroy ; Server telling that Wi. Z changed his nickname to Kilroy. 17

Weitere Befehle 1/3 3. 1 Connection Registration 3. 1. 1 Password message 3. 1.

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 18

Weitere Befehle 2/3 3. 3 Sending messages 3. 3. 1 Private messages 3. 3.

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 19

Weitere Befehle 3/3 3. 6 User based queries 3. 6. 1 Who query 3.

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 20

Software Architektur. User. List 1 1 1 Server 1 1 RDParser 1 * Client.

Software Architektur. User. List 1 1 1 Server 1 1 RDParser 1 * Client. Handler 1 1 1 Registration. Processo r 1 * User 1 44. . Command. Processor 21

User Die Klasse User verwaltet userbezogene Informationen. public class User { public String m.

User Die Klasse User verwaltet userbezogene Informationen. public class User { public String m. Nick; public Client. Handler m. Client. Handler; public String m. Pass; public String m. Username; public String m. Hostname; public String m. Realname; public String m. Mode; public Message. Node m. Last. Message; public String m. Internet. Adress; } 22

Server Der Server erzeugt einen Server. Socket auf dem IRC Port 6667. Für jede

Server Der Server erzeugt einen Server. Socket auf dem IRC Port 6667. Für jede ankommende Verbindung wird ein eigener Client. Handler erzeugt. while (m. Running){ new Client. Handler(l. Server. Socket. accept(), this); } Weiterhin stellt der Server Zentrale Informationen zur Verfügung, wie die Liste der aktuell verbundenen Clients. public public String get. Name() String get. Server. Adress. String() int get. Server. Port() User. List get. User. List() 23

Client. Handler 1/3 Jeder Client erhält einen eigenen Client. Handler, der als nebenläufiger Prozess

Client. Handler 1/3 Jeder Client erhält einen eigenen Client. Handler, der als nebenläufiger Prozess alle Eingabezeichen des Clients aus dem Input. Stream des Sockets liest, bis das Ende einer Message erreicht wird und anschließend parst. public synchronized Message. Node get. Next. Message. Node() throws Syntax. Exception, IOException{ String. Buffer l. Input. Buffer = new String. Buffer(); int l. Read. Byte; while ( (l. Read. Byte = m. Input. Reader. read()) != -1){ l. Input. Buffer. append((char)l. Read. Byte); if (l. Input. Buffer. index. Of(Lexical. Symbols. STRING_LF)>-1) break; } if (l. Read. Byte==-1) m. User. m. Last. Message = null; else m. User. m. Last. Message = (Message. Node) m. Server. parse(l. Input. Buffer. to. String()); return m. User. m. Last. Message; } 24

Client. Handler 2/3 Weitere Methoden ermöglichen das Senden von Nachrichten über den Output. Steam:

Client. Handler 2/3 Weitere Methoden ermöglichen das Senden von Nachrichten über den Output. Steam: public synchronized void send. Message(String p. Message){ Log. get. Instance(). writeln(to. String()+" sending: "+p. Message); m. Print. Writer. print(p. Message+Lexical. Symbols. STRING_CRLF); m. Print. Writer. flush(); } public synchronized void send. Numeric. Reply(String [] p. Number){ send. Message(Numeric. Replies. get. Numeric. Reply. Message(p. Number, m. User)); } 25

Client. Handler 3/3 try { Registration. Processor l. Registration = new Registration. Processor(); l.

Client. Handler 3/3 try { Registration. Processor l. Registration = new Registration. Processor(); l. Registration. process(m. User, null); while (m. Running){ // read next message from client try { l. Message = get. Next. Message. Node(); if (l. Message==null)m. Running = false; if (m. Command. Processors. contains. Key(l. Message. get. Command(). to. Upper. Case() )){ l. Command. Processor = (ICommand. Processor) m. Command. Processors. get(l. Message. get. Command(). to. Upper. Case()); l. Command. Processor. process(m. User, l. Message); } } catch (Syntax. Exception e) { Log. get. Instance(). writeln("Parse. Exception: "+e. to. String()); send. Numeric. Reply(Numeric. Replies. ERR_NEEDMOREPARAMS); } 26

ICommand. Processor public interface ICommand. Processor { public void process(User p. User, Message. Node

ICommand. Processor public interface ICommand. Processor { public void process(User p. User, Message. Node p. Message. Node) throws IOException; public String get. Command. String(); } 27

Nick. Processor public void process(User p. User, Message. Node p. Message. Node) throws IOException

Nick. Processor public void process(User p. User, Message. Node p. Message. Node) throws IOException { String l. New. Nick = p. Message. Node. get. Param(0); if (l. New. Nick != null){ User. List l. List = p. User. m. Client. Handler. get. Server(). get. User. List(); l. List. rename. User(p. User, l. New. Nick); // TODO broadcast new nick of user } else p. User. m. Client. Handler. send. Numeric. Reply( Numeric. Replies. ERR_NONICKNAMEGIVEN); } public String get. Command. String() { return Command. Strings. NICK; } 28

Ping. Processor public void process(User p. User, Message. Node p. Message. Node) throws IOException

Ping. Processor public void process(User p. User, Message. Node p. Message. Node) throws IOException { // PING : 4048004 E // PONG : 4048004 E String l. Ping. Code = p. Message. Node. get. Param(0); if (l. Ping. Code != null) p. User. m. Client. Handler. send. Message("PONG : "+l. Ping. Code); else p. User. m. Client. Handler. send. Message("PONG"); } public String get. Command. String() { return Command. Strings. PING; } 29

Auszug einer Login-Prozedur 1/2 Client connected: 127. 0. 0. 1 Client. Handler 127. 0.

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

Auszug einer Login-Prozedur 2/2 Client. Handler test sending: : 127. 0. 0. 1 004

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

TODO • • • Weitere IRC Befehle über die Schnittstelle ICommand. Processor implementieren Channel

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

Referenzen j. Irc. SX – www. graviton. de/ai/c-und-i Der in diesem Projekt entstehende IRC-Server

Referenzen j. Irc. SX – www. graviton. de/ai/c-und-i Der in diesem Projekt entstehende IRC-Server Bitch. X – www. bitchx. org DOS IRC Client für Unix/Linux/Mac. OS/Windows m. IRC - www. mirc. com IRC Client mit GUI für Windows RFC Archiv - www. faqs. org/rfcs j. Flex – jflex. de Java Scanner Generator 33