Broad Network


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

This is part 4 of my series, Writing MySQL Protocol Packets in PurePerl. In this part of the series, I explain how to produce the MySQL Greeting Packet in PurePerl. PurePerl stands for Pure Perl and it means Perl software without any C software underneath. You should have read the previous parts of the series before reaching here, as this is a continuation.

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.
Table 4.1. Fields of the Server's Greeting Packet
Offset
in the body
LengthDescription
01Protocol version number. Decimal 10 (0x0A) in recent versions.
1ver_len = strlen (server_version) + 1Zero-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 4Internal MySQL ID of the thread that is handling this connection. Low byte first.
ver_len + 5 9In 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 + 142Server capabilities bit mask with the low byte first.
ver_len + 16 1Default 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 2The 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 + 1913Reserved for future use. Currently zeroed out – each byte is 0x00.
ver_len + 32 13Present 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.

Zero-terminated means the extra byte is 00000000 in bits, that is 0x00 in hex. Zero byte means the same value. The character for zero terminated byte is '\0', where 0 is zero and not letter, O.

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 Perl
Perl 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

Comments

Become the Writer's Fan
Send the Writer a Message