Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Using XML-RPC for Web services: XML-RPC Middleware

Part 2 of Using XML-RPC for Web services

Return to article


Listing 2: Perl XML-RPC Listener

<![if !supportEmptyParas]> <![endif]>
       1               #!/usr/bin/perl --
       2               # XML-RPC listener that brokers account request
       3                      
       4               use strict;
       5               use warnings;
       6               use Frontier::Daemon;
       7               use DBI;
       8                      
       9               # Start a global connection to mysql
      10              my $Dbh = DBI->connect('dbi:mysql:accounts:marian.daisypark.net', 'web', '');
      11              unless( defined $Dbh ){
      12                  die "ERROR: Can't connect to mysql database on marian";
      13              }
      14                    
      15              Frontier::Daemon->new(
      16                                                              methods => {
      17                                                                              authenticate       => \&authenticate,
      18                                                                              get_account_info => \&get_account_info,
      19                                                                              set_account_info => \&set_account_info,
      20                                                              },
      21                                                              LocalHost     => 'marian.daisypark.net',
      22                                                              LocalPort     => 1080,            23                                                             );
      24                    
      25              sub END {
      26                  if( defined $Dbh ){
      27                    $Dbh->do("Unlock Tables");
      28                    $Dbh->disconnect;
      29                  }
      30              }
      31                    
      32              #---------------------------------
      33              # Remote procedure implementation
      34              #---------------------------------
      35                    
      36              sub authenticate {
      37                  my ($username, $password) = @_;
      38                    
      39                  die "Please supply a valid password" unless validate_password($password);
      40                  die "Please supply a valid username" unless validate_username($username);
      41                    
      42                  # Ok to proceed
      43                  my $enc_password;
      44                  my $sth = $Dbh->prepare("Select password From users Where username=?");       45                  die "Oops! no statement handle" unless $sth;
      46                    
      47                  $sth->execute( $username );
      48                  $sth->bind_col(1,\$enc_password);
      49                  $sth->fetch;
      50                        
      51                  if( ! defined $enc_password ){
      52                    die "Couldn't fetch password for '$username'";
      53                  }
      54                    
      55                  # This password is DES encrypted
      56                  my $in = crypt( $password, substr($enc_password, 0, 2) );
      57                  if( $enc_password eq $in ){
      58                    logger( $username, 'LOGIN');
      59                    return new_session_id($username);
      60                  }else{
      61                    return 0;
      62                  }
      63                    
      64              }
      65                    66              sub get_account_info {
      67                  my ($sid) = @_;
      68                    
      69                  die "Please supply a positive integer greater than 0" if $sid < 1;            70                    
      71                  my $sth = $Dbh->prepare(<<EOT);
      72              Select users.username,fullname,points From sessions
      73                  Left Join users On sessions.username = users.username
      74                  Where sessions.id = ?
      75              EOT
      76                   
      77                  unless( $sth ){
      78                    warn "\$sth in get_account_info failed\n";
      79                  }
      80                    
      81                  $sth->execute($sid) || die "Error: ". $sth->errstr();
      82                    
      83                  my $hr = $sth->fetchrow_hashref; # should only be one
      84                  unless( ref $hr ){
      85                    warn "Couldn't find any rows for SID=$sid'";
      86                    return {}
      87                  }
      88                  return $hr;
      89              }
      90                    
      91              sub set_account_info {
      92                  my ($user_rec) = @_;
      93                  my %user_rec = %{$user_rec};
      94                    
      95                  # Make sure everything seems normal
      96                  unless(validate_username($user_rec{username})){
      97                    die "Username must be less than 13 characters(not $user_rec{username})";
      98                  }
      99                       
     100                 # this number will overflow mysql table (signed int)
     101                 $user_rec{points} = $user_rec{points} % 2_000_000_000;
     102                  
     103                 unless( $Dbh->do("Lock Tables users WRITE") ){
     104                   die "Couldn't lock users table!";
     105                 }
     106                  
     107                 # Could be an update
     108                 my $count = $Dbh->do("select * from users where username=".
     109                                                              $Dbh->quote($user_rec{username}) );
     110                  
     111                 # Sanity check, $count > 1 is an error!
     112                 if( $count > 0){
     113                   # This is an update (no password update!)
     114                   my $sth = $Dbh->prepare(<<EOT);
     115             Update users set fullname=?,points=?
     116             where username=?
     117             EOT
     118                   # lock the table during the update
     119                   my $rc = $sth->execute(@user_rec{
     120                                                                                                      'fullname',
     121                                                                                                      'points'
     122                                                                                                     }, $user_rec{username}
     123                                                                             );
     124                  
     125                   $Dbh->do("Unlock Tables");
     126                   logger( $user_rec{username}, 'UPDATED USERINFO');
     127                  
     128                   if($rc){
     129                     return 1;
     130                   }else{
     131                     return 0;
     132                   }
     133                        
     134                 }else{
     135                   # This is a new user, don't need tables locked for this
     136                   $Dbh->do("Unlock Tables");
     137                   logger( $user_rec{username}, 'ADDED USER');
     138                  
     139                   # Encrypt the plain text password
     140                   my $salt = join '', ("a".."z")[ rand(26), rand(26) ];
     141                   $user_rec{password} = crypt($user_rec{password}, $salt);
     142                  
     143                  
     144                   my $sth = $Dbh->prepare(<<EOT);
     145             Insert into users (username,password,fullname,points) VALUES (?,?,?,?)          146             EOT
     147                   if( $sth->execute(
     148                                                             @user_rec{'username',          149                                                                                               'password',
     150                                                                                               'fullname',
     151                                                                                               'points'
     152                                                                                              }
     153                                                            )){
     154                     return 1;
     155                   }else{
     156                     return 0;
     157                   }
     158                 }
     159             }
     160                  
     161             #--------------------------
     162             # Helper Functions
     163             #--------------------------
     164             sub validate_username {
     165                 my ($usr) = @_;
     166                  
     167                 if( ! defined $usr || length($usr) > 12){
     168                   return 0;
     169                 }else{
     170                   return 1;
     171                 }
     172             }
     173                  
     174             sub validate_password {
     175                 my ($pass) = @_;
     176                 if( ! defined $pass || length($pass) > 13 ) {
     177                   return 0;
     178                 }else{
     179                   return 1;
     180                 }
     181             }
     182                  
     183             sub validate_fullname {
     184                 my ($fullname) = @_;
     185                  
     186                 if( ! defined $fullname || length($fullname) > 50 ){
     187                   return 0;
     188                 }else{
     189                   return 1;
     190                 }
     191             }
     192                  
     193             sub logger {
     194                 my ($username, $action) = @_;
     195                      
     196                 return unless validate_username( $username );
     197                 return if length($action) > 25;
     198                 my $sth = $Dbh->prepare("insert into logins (username,action) VALUES (?,?)");                       
     199                 unless( $sth ){
     200                   warn "Prepare failed: ", $Dbh->errstr();
     201                   return;
     202                 }
     203                 unless( $sth->execute( $username, $action ) ){
     204                   warn "execute failed: ", $sth->errstr();
     205                   return;
     206                 }
     207                 return 1;
     208             }
     209                  
     210             sub new_session_id {
     211                 my ($username) = @_; # Already should have check for valid username           212                      
     213                 my $sth = $Dbh->prepare("Insert into sessions (username) VALUES (?)");        214                 $sth->execute($username);
     215                      
     216                 return $Dbh->{mysql_insertid};
     217             }

Return to article