MySQL Greeting Packet in PurePerl
Writing MySQL Protocol Packets in PurePerl – Part 4
Writing a Perl Module
Foreword: In this part of the series, I explain how to produce the MySQL Greeting Packet in PurePerl.
By: Chrysanthus Date Published: 28 Jan 2015
Introduction
If the socket connection from the client to the server is successful, the server will send a greeting packet to the client. This is the first packet sent in the authentication process. The connection process establishes a connection without really sending a packet. The greeting packet sent from the server software to the client software is a string of bytes. It begins with a header segment followed by the body segment. All packets consist of the header segment and the body segment.
Packet Body Byte Arrangement
In the body segment of the greeting packet string, the consecutive byte sequences, their lengths and their purposes are as in the following table. Each byte sequence is called a field.
Offset in the body | Length | Description |
---|---|---|
0 | 1 | Protocol version number. Decimal 10 (0x0A) in recent versions. |
1 | ver_len = strlen (server_version) + 1 | Zero-terminated server version string. The length is variable, and is calculated according to the formula in the Length column. The subsequent offsets depend on the length of this field. |
ver_len + 1 | 4 | Internal MySQL ID of the thread that is handling this connection. Low byte first. |
ver_len + 5 | 9 | In MySQL version 4.0 and earlier, the random seed string in its entirety. In 4.1 and later, the first 8 bytes of the 20-byte random seed string. At the end is a terminating zero. With the terminating zero byte, the length of the string is one greater than the useful length. |
ver_len + 14 | 2 | Server capabilities bit mask with the low byte first. |
ver_len + 16 | 1 | Default character set code, or more precisely, the code of the default collation. A character set collation is a set of rules that defines a sequential order among characters. |
ver_len + 17 | 2 | The server status bit mask with the low byte first. Reports whether the server is in transaction or autocommit mode, if there are additional results from a multistatement query, or if a good index (or some index) was used for query optimization. |
ver_len + 19 | 13 | Reserved for future use. Currently zeroed out – each byte is 0x00. |
ver_len + 32 | 13 | Present only in version 4.1 and later. The rest of the random seed string terminated with a zero byte. The length is greater by 1 because of the terminating zero byte. |
The PurePerl Code
The Perl package I designed to produce the packet is called, Greeting and its file name is, Greeting.pm. The package is part of the client software. The package has one function. The function takes as argument the string (packet) sent by the server. It then extracts the components outlined in the above table and returns the components in a hash (i.e the function returns a hash). For some components the byte order is reversed and even converted into decimal. The scramble message comes in two fields. The values of the two fields have to be joined first before being returned by the function. The complete code is given below. If you have been reading this volume and its series in the order given, then you should be able to understand the code. It is:
package Greeting;
our $VERSION = "1.01";
use strict;
sub greet
{
my $greet_len = length($_[0]);
my ($body_len1, $body_len2, $body_len3, $seq_no, $prot_vers_no) = unpack('H2H2H2H2H2', $_[0]);
my $body_len_HBF = $body_len3 . $body_len2 . $body_len1;
my $body_len_D = hex($body_len_HBF);
my $srv_vers_B_Len = index($_[0], "\0", 5) - 4;
my $templ_srv_vers = "x5A" . $srv_vers_B_Len;
my $srv_vers = unpack($templ_srv_vers, $_[0]);
my $templ_ID = "A" . (5+$srv_vers_B_Len) . "AAAA";
my ($dummy, $ID1,$ID2,$ID3,$ID4) = unpack($templ_ID, $_[0]);
my $ID_HBF = $ID4 . $ID3 . $ID2 . $ID1;
my $ID = $ID_HBF;
my $templ_scramble1 = "x5x" . $srv_vers_B_Len . "x4A8";
my $scramble1_B = unpack($templ_scramble1, $_[0]);
my $templ_srv_cap_bit_msk = "x5x" . $srv_vers_B_Len . "x4x9AA";
my ($srv_cap_bit_msk1,$srv_cap_bit_msk2) = unpack($templ_srv_cap_bit_msk, $_[0]);
my $srv_cap_bit_msk_HBF = $srv_cap_bit_msk2 . $srv_cap_bit_msk1;
my $templ_def_char_set_col = "x5x" . $srv_vers_B_Len . "x4x9x2A";
my $def_char_set_col = unpack($templ_def_char_set_col, $_[0]);
my $templ_srv_st_bit_msk = "x5x" . $srv_vers_B_Len . "x4x9x2xAA";
my ($srv_st_bit_msk1,$srv_st_bit_msk2) = unpack($templ_srv_st_bit_msk, $_[0]);
my $srv_st_bit_msk_HBF = $srv_st_bit_msk2 . $srv_st_bit_msk1;
my $templ_scramble2 = "x5x" . $srv_vers_B_Len . "x4x9x2x3x13A12";
my $scramble2_B = unpack($templ_scramble2, $_[0]);
my $scramble = $scramble1_B . $scramble2_B;
my %ha = (
body_len_D => $body_len_D,
seq_no => hex($seq_no),
prot_vers_no => hex($prot_vers_no),
srv_vers => $srv_vers,
ID => $ID,
srv_cap_bit_msk_HBF => $srv_cap_bit_msk_HBF,
def_char_set_col => $def_char_set_col,
srv_st_bit_msk_HBF => $srv_st_bit_msk_HBF,
scramble => $scramble
);
return %ha;
}
1;
If you are not using AcivePerl, then you should precede the package with something like, #!/usr/bin/perl .
That is it for this part of the series. We stop here and continue in the next part.
Chrys
Related Links
Internet Sockets and PerlPerl pack and unpack Functions
Writing MySQL Protocol Packets in PurePerl
Developing a PurePerl MySQL API
Using the PurePerl MySQL API
More Related Links
Perl Mailsend
PurePerl MySQL API
Perl Course - Professional and Advanced
Major in Website Design
Web Development Course
Producing a Pure Perl Library
MySQL Course
BACK NEXT