network subsystem: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
__TOC__ | __TOC__ | ||
== Overview == | |||
The OpenKore network subsystem roughly consists of the following classes: | The OpenKore network subsystem roughly consists of the following classes: | ||
Line 47: | Line 49: | ||
Note that none of these classes, from the connection manager to the serverType descriptions, should contain any AI code. | Note that none of these classes, from the connection manager to the serverType descriptions, should contain any AI code. | ||
=== How it all works together === | |||
Main initialization code creates a connection manager instance and a message tokenizer instance: | |||
$net = new Network::DirectConnection; | |||
$incomingMessages = new Network::MessageTokenizer(\%recvpackets); | |||
Connection manager creates a packet parser instance: | |||
$packetParser = Network::Receive->create($wrapper, $serverType); | |||
Main loop passes information from connection manager ''$net'' to message tokenizer ''$incomingMessages'': | |||
$incomingMessages->add($net->serverRecv); | |||
Message tokenizer with data and a message handler ''$packetParser'' are passed to a packet parser ''$packetParser'' to process all available messages: | |||
@packets = $packetParser->process($incomingMessages, $packetParser); | |||
# compare with outgoing packets: | |||
# @packets = $messageSender->process($outgoingClientMessages, $clientPacketHandler); | |||
Packets are passed back to the connection manager, which passes them to [[XKore]] clients: | |||
$net->clientSend($_) for @packets; | |||
Meanwhile, the packet parser calls custom parsers, hooks and built-in handlers: | |||
my $custom_parser = $self->can("parse_$handler_name") | |||
if ($custom_parser) { | |||
$self->$custom_parser(\%args); | |||
} | |||
Plugins::callHook("packet_pre/$handler_name", \%args); | |||
my $handler = $messageHandler->can($handler_name); | |||
if ($handler) { | |||
$messageHandler->$handler(\%args); | |||
} | |||
Plugins::callHook("packet/$handler_name", \%args); | |||
== Handling multiple server types (message parser part) == | == Handling multiple server types (message parser part) == |
Revision as of 09:36, 23 November 2012
Overview
The OpenKore network subsystem roughly consists of the following classes:
The Network class
This is the connection manager. It manages the TCP/IP socket connection with the server, and handles things like connection, disconnection, sending data to the server, receiving data from the server, etc. But it doesn't do much else.
Schematically, it looks like this:
Upon connection to the server, it creates two objects:
- A message parser object, which is of class Network::Receive::ServerTypeX. Whenever a message is received from the server, that message is passed to the message parser.
- A message sender object (not seen in the above diagram), which is of class Network::Send::ServerTypeX. This is used for sending messages to the server.
There are several implementations of Network class: Network::DirectConnection, Network::XKore and Network::XKoreProxy.
The Network::MessageTokenizer class
This is a tokenizer class. It extracts discrete server or client messages from a byte stream passed by the connection manager. But it doesn't do much else.
The Network::PacketParser class
This is a base message parser class. It parses messages passed by the connection manager into hashes with message data, as well as does reverse operation - generates messages from hashes with message data. But it doesn't do much else.
Afterwards, parsed messages are handled by built-in handlers in following classes and, with hooks, by plugins or other modules.
Additionally, there is API for modifying or dropping messages to alter any further processing.
The Network::Receive, Network::Send and Network::ClientReceive classes
There classes are descendants of Network::PacketParser class.
Network::Receive and Network::Send are parser helper classes. They contain parser helpers which serve as a workaround in the absense of the capable parser subsystem.
Network::Receive and Network::ClientReceive are message handling classes. They contain built-in handlers for messages coming from the server (Network::Receive) or from the client (Network::ClientReceive), which store information from network messages to be used later in other modules (like the AI).
Network::Send is the message sender class. It encapsulates network messages into simple, easy-to-use functions to be used outside of network subsystem.
Any descendant ServerType class may customize message handlers and parser helpers, but they should refrain from that other than for servertype-specific features and debugging.
The Network::Receive::ServerTypeX and Network::Send::ServerTypeX class
These are serverType description classes. They describe network message identifiers and structures for different servers. But they shouldn't do much else.
Note that none of these classes, from the connection manager to the serverType descriptions, should contain any AI code.
How it all works together
Main initialization code creates a connection manager instance and a message tokenizer instance:
$net = new Network::DirectConnection; $incomingMessages = new Network::MessageTokenizer(\%recvpackets);
Connection manager creates a packet parser instance:
$packetParser = Network::Receive->create($wrapper, $serverType);
Main loop passes information from connection manager $net to message tokenizer $incomingMessages:
$incomingMessages->add($net->serverRecv);
Message tokenizer with data and a message handler $packetParser are passed to a packet parser $packetParser to process all available messages:
@packets = $packetParser->process($incomingMessages, $packetParser); # compare with outgoing packets: # @packets = $messageSender->process($outgoingClientMessages, $clientPacketHandler);
Packets are passed back to the connection manager, which passes them to XKore clients:
$net->clientSend($_) for @packets;
Meanwhile, the packet parser calls custom parsers, hooks and built-in handlers:
my $custom_parser = $self->can("parse_$handler_name") if ($custom_parser) { $self->$custom_parser(\%args); } Plugins::callHook("packet_pre/$handler_name", \%args); my $handler = $messageHandler->can($handler_name); if ($handler) { $messageHandler->$handler(\%args); } Plugins::callHook("packet/$handler_name", \%args);
Handling multiple server types (message parser part)
Implementation details
Example 1: adding a new message handler
Example 2: handling a different server type
Handling multiple server types (message sender part)
Using the message sender
Compatibility notes
Hooks
"packet_pre/$HANDLER_NAME"
"packet/$HANDLER_NAME"
Appendix A: introduction to the Ragnarok Online protocol
Appendix B: recvpackets.txt and handling message lengths
Appendix C: obfuscation of outgoing messages
Padded packets
Encrypted message IDs
Original article
http://web.archive.org/web/20090305035837/http://www.openkore.com/wiki/index.php/Network_subsystem