NAME Net::Starnet::DataAccounting - interface to the SDA protocol SYNOPSIS use constant SDA_UPDATE_TIME 60; my $sda = Net::Starnet::DataAccounting->new( user => $user, pass => $pass, verbose => $VERBOSE, login => \&login, logout => \&logout, update => \&update, (defined($hostname) ? ( host => $hostname ) : ()), (defined($server) ? ( server => $server ) : ()), ); my $connected = $sda->login(); if ($connected) { $SIG{INT} = $SIG{TERM} = sub { $sda->logout(); exit 0; }; while ($connected) { sleep SDA_UPDATE_TIME; $connected = $sda->update(); } my $disconnected = $sda->logout(); } DESCRIPTION The Net::Starnet::DataAccounting module provides an interface to the protocol used by the Starnet Data Accounting System. It allows simple login, logout and health checking. METHODS Net::Starnet::DataAccounting->new( host => $yourhostname, server => $remotehostname, port => $remoteport, user => $username, pass => $password, client => $clientname, login => \&login, logout => \&logout, update => \&update, verbose => $verbose, ) Creates a new SDA connection. Host and server should be either IPs or hostnames. Port is a port number, user and pass are the appropriate username and password. Client is a custom client string for the connection to use. Login, logout and update are routines that will be called after an attempt to send the appropriate message. The routines in question will be passed two parameters: the SDA object and the text response from the server (decoded). Verbose determines whether debugging information will be shown. $sda->verbose($value|) If given a parameter, sets the verbosity. Returns the verbosity in all cases. $sda->login() Directs the SDA object to attempt to connect to the server. Calls the login routine specified on construction after the attempt is made. $sda->logout() Directs the SDA object to attempt to disconnect to the server. Calls the logout routine specified on construction after the attempt is made. $sda->update() Directs the SDA object to attempt to update the client's status on the server. Calls the update routine specified on construction after the attempt is made. This function should be called every two minutes or so; ideally more frequently. PROTOCOL NOTES At the basic level, SDA clients operate by sending a line of text to the server and receiving a line of text in response. Data Encoding The lines bandied between the client and server are encoded using a very simple algorithm. The offset of a given byte in the buffer, modulo 7, is added to the ASCII value of the byte in question. Decoding is thus the reverse. A suitable regular expression, assuming $i is initialised to 0 on entry, would be: s/(.)/chr ord($1)-$i++%7/eg; And, in fact, that is the regexp this program makes use of. Request Line Contents The general form of the request line is: /^$type $user $pass $ip 0 $client $/ /^(\d) ([a-zA-Z_]) (\d{6}) ($ip_RE) 0 (\S+) $/ The type indicates the type of command the client is attempting to execute. It is a single digit. The appropriate values are: 1 - login 2 - logout 3 - update The username is a string, typically a maximum of 8 characters and only containing [a-zA-Z0-9]. The username is partially case sensitive. In a given session, you should use consistent casing since the server pays attention to it. If you attempt to use two sessions with the same casing simultaneously, you will receive an 'Already logged on' error. Modifying the case of arbitrary letters resolves that, thus enabling one to login in multiple locations. Empirically, the password is a numeric sequence, 6 digits long. This is to enable SDA to hook into the Starnet StarCom package (the password is also used as a phone external dial-out code). The IP is the IP of the machine to which you would like your data quota to be used by. This does not have to be the machine from which you run the client, although it typically is. It is unknown what the '0' indicates. The client string is an arbitrary string indicating the client name and version (typically). Think of it as the USER_AGENT variable in CGI. These fields are all separated by a space and there is a space at the end as well. The client only ever sends these lines. Thus the communication protocol can be easily abstracted to merely sending an integer to a generic sda_send() routine and returning the response line (decoded, natch). Response Line Contents /^(\d)\s(\d)\s.*$/ The response line format varies slightly according to operation. Login Event In the event of a login (type 1) event, the server returns: /^$type $success $code $msg$/ /^(\d) (\d) (\d) (.*)$/ Type is 1 - login. Success is either 0 or 1, indicating failure or success respectively. The code depends on the success. If successful, then the code is 0. In event of an error the code is one of the following values: 1 - Incorrect username or password 2 - unknown 3 - No quota available 4 - Already connected Errors 1 and 3 are unrecoverable. In the event of error 1, you should see your administrator, or re-enter your username and password. Error 3 indicates that your administrator needs to add more to your data limit. Error 4 merely indicates that you're already connected and should be regarded as identical to a successful login. It is unknown what an error of type 2 indicates. Logout Event In the event of a login (type 2) event, the server returns: /^$type $success $quota $msg$/ /^(\d) (\d) (-1|\d+\.\d{3}) (.*)$/ Type is 2 - logout. Success is either 0 or 1, indicating failure or success respectively. I am yet to be able to invoke a failure. The only two responses I have been able to invoke are: %.3f Mb Quota_Remaing -1 Logoff_Confirmed where $quota is the -1 or %.3f and $msg is the rest. And, yes, they did misspell 'Remaining'. Update Event In the event of a update (type 3) event, the server returns: /^$type $success $msg$/ /^(\d) (\d) (.*)$/ Type is 3 - update. Success is either 0 or 1, indicating failure or success respectively. In the event of a failure, try to logout. In a successful update, the message is composed of: 0 Quota 24.423Mb; Used 4.523Mb Naturally, where the quantities are relevant to your session. In an unsuccessful update, I have only invoked a 'User Not Found' error. This happens when a user tries to update but isn't actually logged in (or doesn't exist anyway). The message looks like this: Health Check Deny: User Not Found Other situations are, as of yet, unknown. AUTHOR Iain Truskett Please report any bugs, or post any suggestions, to either the mailing list at (email to subscribe) or directly to the author at BUGS Probably doesn't work well on EBCDIC systems due to the encoding/decoding process. PLANS I intend to have the module returning an appropriate response object which can be queried for its contents so that parsing the response line is rendered unnecessary. The object will either be overloaded so code using the existing interface doesn't fall over or a parameter will be added to the new() call. COPYRIGHT Copyright (c) 2001 Iain Truskett. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. $Id: DataAccounting.pm,v 1.2 2002/02/03 14:29:05 koschei Exp $ ACKNOWLEDGEMENTS I would like to thank TBBle for his initial research into the protocol, Starnet for providing such a dodgy protocol, and Bruceo and JT for providing incentive to actually bother to write this program. SEE ALSO