DBIx-MyServer
view release on metacpan or search on metacpan
lib/DBIx/MyServer.pm view on Meta::CPAN
The following parameters are accepted:
C<socket> - the socket that will be used for communication with the client. The socket must be created in advance with
L<socket()> and an incoming connection must be already established using L<accept()>
C<dbh> - a L<DBI> handle. L<DBIx::MyServer> does not use it however it can be used by modules inheriting from L<DBIx::MyServer>
C<parser> - a L<DBIx::MyParser> handle. If you do not override the C<comQuery()> method, this handle will be used to parse the
SQL in order to call the appropriate C<sqlcom...> method.
C<banner> - the server version string that is announced to the client. If not specified, the name and the version of the
L<DBIx::MyServer> module is sent. Some clients, e.g. L<DBD::mysql> attempt to parse that string as a version number in order
to determine the server capabilities. Therefore, it may be a good idea to start your C<banner> with a string in the form
C<5.0.37>. For example, the C<examples/dbi.pl> example takes the C<banner> from the actual MySQL server the connection is
forwarded to. Please note that the MySQL client may isssue a C<select @@version_comment limit 1> command and display the
result to the user.
C<server_charset> - the character set (and collation) the server announces to the client. A number is expected, not
a character set or collation name. To onvert between numbers and names, please consult the C<sql/share/charsets/Index.xml>
file from your MySQL source tree. The numbers are found under the C<id> property of each XML leaf.
Generally you do not need to override the constructor. If you do, please keep in mind that it returns
a blessed C<@ARRAY>, not a blessed C<%HASH>, even though new() accepts an argument hash. This is
done for performance reasons. The first 20 items from the array are reserved for the parent module,
so please put your object properties into the array members from 20 onwards.
=head1 CONNECTION ESTABLISHMENT
You are responsible for opening your listening socket and accepting a connection on it (and possibly forking
a child process). Once the connection has been accepted, you create a C<DBIx::MyServer> object and pass the socket
to it. From then on, you have two options:
=head2 Procedural Connection Establishment
If you want to handle connection establishment yourself, you will need to call those two functions consequtively.
Please see C<examples/echo.pl> for a script that uses procedural connection establishment.
=item C<< $myserver->sendServerHello() >>
The server is the one that initiates the handshake by sending his greeting to the client.
=item C<< my ($username, $database) = $myserver->readClientHello() >>
The client provides his username and the database it wants to connect to. If C<$username> is C<undef>, the client
disconnected before authenticating. To check the password, use C<$myserver->passwordMatches($correct_password)
which will return C<1> if the password provided by the client is correct and C<undef> otherwise.
If you need to know the IP of the client, you need to extract it from the socket that you established yourself.
Please check out the implementation of C<DBIx::MyParse::handshake()> for the correct way to call C<getpeername()>.
The socket being serviced by the current C<DBIx::MyParse> object can be obtained by calling C<getSocket()>.
If you want to let the client in, do a C<< $myserver->sendOK() >>. Otherwise, use C<< $myserver->sendError() >> as described below.
=head2 Connection Establishment with Subclassing
If you are subclassing C<DBIx::MyParse>, the way C<DBIx::MyParse::DBI> does, to establish a connection you call:
=item C<< $myserver->handshake() >>
which completes the handshake between the two parties. The return value will be C<undef> if some I/O error
occured, or the result of the client authorization routine. When the client sends its credentials, the
module will call:
=item C<< $myserver->authorize($remote_host, $username, $database) >>
whose default action is to accept only localhost connections regardless of username or password. You should
override this method to install your own security requirements. If your C<authorize()> returns C<undef>, the
connection will be rejected, if it returns anything else, the connection will be completed and the return
value will be passed back to the caller of C<handshake()>. You can use this return value to communicate the
access rights the particular user is entitled to, so that your script can know them and enforce them.
In case you want to reject the connection, you need to send your own error message via C<sendError()>. If
you accept the connection, the module will send the C<OK> message back to the client for you.
The password supplied by the client is irreversibly encrypted, therefore to verify it, you need to use:
=item C<< $myserver->passwordMatches($expected_password) >>
which will return C<undef> if the password does not match and C<1> otherwise.
If the client supplied a database name on connect, C<comInitDb($database)> will be called.
For an example of a custom C<authorize()>, please see C<DBIx::MyParse::DBI> which does some extra connection setup.
=head1 COMMAND PROCESSING
=head2 Procedural Command Processing
If you want to handle each command individually on your own, you need to call
=item C<< my ($command, $data) = $myserver->readCommand() >>
in a loop and process each command. Sending result sets and errors and terminating the connection is entirely up to you.
The C<examples/odbc.pl> script uses this approach to process queries in the simples possible way without reflecting much
on their contents.
=head2 Command Processing with Subclassing
If you are subclassing C<DBIx::MyParse>, your main script needs to call:
=item C<< $myserver->processCommand() >>
in a loop. The default C<processCommand()> handler will obtain the next command from the client using C<readCommand()>
and will call the appropriate individual command handler, described below. You can override C<processCommand()> if
you want to process the entire packet yourself, in which case you are responsible for calling C<readCommand()> yourself.
C<processCommand()> will return whatever the individual command handler returned. C<undef> is reserved for I/O errors,
which will allow you to conveniently exit your loop. Therefore it is recommended that any handlers that you
override return C<1> to indicate correct operation or non-fatal errors.
=head1 INDIVIDUAL COMMAND HANDLERS
If you do not override the generic C<< processCommand() >> method, the following individual handlers will
be called depending on the actual MySQL command received by the server. The default action of those handlers is
to send a "command unsupported" error back to the client, unless specified otherwise below.
If you want to send an error or an OK message to the client as a response to a command or query, you need to use
C<sendOK()> and C<sendError()> yourself. The parent module will not send any of those for you under no circumstances.
=item C<< $myserver->comSleep($data) >>
( run in 0.632 second using v1.01-cache-2.11-cpan-5837b0d9d2c )