MessageTokenizer.pm
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:5k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Networking subsystem
  3. #  This module contains functions for sending packets to the server.
  4. #
  5. #  This software is open source, licensed under the GNU General Public
  6. #  License, version 2.
  7. #  Basically, this means that you're allowed to modify and distribute
  8. #  this software. However, if you distribute modified versions, you MUST
  9. #  also distribute the source code.
  10. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  11. #########################################################################
  12. ##
  13. # MODULE DESCRIPTION: Conversion of byte stream to descrete messages.
  14. #
  15. # As explained by the <a href="http://www.openkore.com/wiki/index.php/Network_subsystem">
  16. # network subsystem overview</a>, the Ragnarok Online protocol uses TCP, which means
  17. # that all server messages are received as a byte stream.
  18. # This class is specialized in extracting discrete RO server or client messages from a byte
  19. # stream.
  20. package Network::MessageTokenizer;
  21. use strict;
  22. use Carp::Assert;
  23. use Modules 'register';
  24. use bytes;
  25. no encoding 'utf8';
  26. use enum qw(KNOWN_MESSAGE UNKNOWN_MESSAGE ACCOUNT_ID);
  27. ##
  28. # Network::MessageTokenizer->new(Hash* rpackets)
  29. # rpackets: A reference to a hash containing the packet length database.
  30. # Required: defined($rpackets)
  31. #
  32. # Create a new Network::MessageTokenizer object.
  33. sub new {
  34. my ($class, $rpackets) = @_;
  35. assert(defined $rpackets) if DEBUG;
  36. my %self = (
  37. rpackets => $rpackets,
  38. buffer => ''
  39. );
  40. return bless %self, $class;
  41. }
  42. ##
  43. # void $Network_MessageTokenizer->add(Bytes data)
  44. # Requires: defined($data)
  45. #
  46. # Add raw data to this tokenizer's buffer.
  47. sub add {
  48. my ($self, $data) = @_;
  49. assert(defined $data) if DEBUG;
  50. $self->{buffer} .= $data;
  51. }
  52. ##
  53. # void $Network_MessageTokenizer->clear([int size])
  54. # Requires: size >= 0
  55. #
  56. # Clear the internal buffer. If $size is given, only the first $size
  57. # bytes are removed.
  58. sub clear {
  59. my ($self, $size) = @_;
  60. if (defined $size) {
  61. substr($_[0]->{buffer}, 0, $size, '');
  62. } else {
  63. $_[0]->{buffer} = '';
  64. }
  65. }
  66. ##
  67. # void $Network_MessageTokenizer->nextMessageMightBeAccountID()
  68. #
  69. # Tell this tokenizer that the next message might be the account ID.
  70. sub nextMessageMightBeAccountID {
  71. my ($self) = @_;
  72. $self->{nextMessageMightBeAccountID} = 1;
  73. }
  74. ##
  75. # String Network::MessageTokenizer::getMessageID(Bytes message)
  76. # Requires: length($message) >= 2
  77. #
  78. # Extract the message ID (also known as the "packet switch") from the given message.
  79. sub getMessageID {
  80. return uc(unpack("H2", substr($_[0], 1, 1))) . uc(unpack("H2", substr($_[0], 0, 1)));
  81. }
  82. ##
  83. # Bytes $Network->MessageTokenizer->getBuffer()
  84. # Ensures: defined(result)
  85. #
  86. # Get the internal buffer.
  87. sub getBuffer {
  88. return $_[0]->{buffer};
  89. }
  90. ##
  91. # Bytes $Network_MessageTokenizer->readNext(int* type)
  92. #
  93. # Read the next full message from the buffer, if there is one.
  94. # If not, undef will be returned.
  95. #
  96. # The message's type will be returned via the type parameter.
  97. # It will be one of:
  98. # `l
  99. # - KNOWN_MESSAGE - This is a known message, i.e. we know its length.
  100. # - UNKNOWN_MESSAGE - This is an unknown message, i.e. we don't know its length.
  101. # - ACCOUNT_ID - This is an account ID.
  102. # `l`
  103. sub readNext {
  104. my ($self, $type) = @_;
  105. my $buffer = $self->{buffer};
  106. return undef if (length($$buffer) < 2);
  107. my $switch = getMessageID($$buffer);
  108. my $rpackets = $self->{rpackets};
  109. my $size = $rpackets->{$switch};
  110. my $result;
  111. my $nextMessageMightBeAccountID = $self->{nextMessageMightBeAccountID};
  112. $self->{nextMessageMightBeAccountID} = undef;
  113. if ($nextMessageMightBeAccountID) {
  114. if (length($$buffer) >= 4) {
  115. $result = substr($$buffer, 0, 4);
  116. if (unpack("V1",$result) == unpack("V1",$Globals::accountID)) {
  117. substr($$buffer, 0, 4, '');
  118. $$type = ACCOUNT_ID;
  119. } else {
  120. $$type = KNOWN_MESSAGE; # Account ID is "hidden" in a packet (0283 is one of them)
  121. return;
  122. }
  123. } else {
  124. $self->{nextMessageMightBeAccountID} = $nextMessageMightBeAccountID;
  125. }
  126. } elsif ($size > 1) {
  127. # Static length message.
  128. if (length($$buffer) >= $size) {
  129. $result = substr($$buffer, 0, $size);
  130. substr($$buffer, 0, $size, '');
  131. $$type = KNOWN_MESSAGE;
  132. }
  133. } elsif (defined($size) && $size == 0) {
  134. # Variable length message.
  135. if (length($$buffer) >= 4) {
  136. $size = unpack("v", substr($$buffer, 2, 2));
  137. if (length($$buffer) >= $size) {
  138. $result = substr($$buffer, 0, $size);
  139. substr($$buffer, 0, $size, '');
  140. $$type = KNOWN_MESSAGE;
  141. }
  142. }
  143. } else {
  144. $result = $$buffer;
  145. $self->{buffer} = '';
  146. $$type = UNKNOWN_MESSAGE;
  147. }
  148. return $result;
  149. }
  150. 1;