--- RasLoadTester/ras-load	2025/02/08 23:09:15	1.1
+++ RasLoadTester/ras-load	2025/02/09 03:28:53	1.3
@@ -1,5 +1,24 @@
 #!/usr/bin/env perl
 
+# 
+# ChivaNet Load Tester
+#  Copyright (C) 2025 Coherent Logic Development LLC
+#
+# Author: Serena Willis <snw@coherent-logic.com>
+#
+# Licensed AGPL-3.0
+#
+#   $Log: ras-load,v $
+#   Revision 1.3  2025/02/09 03:28:53  snw
+#   Increase heartbeat response failure threshold from 5 to 60 secs
+#
+#   Revision 1.2  2025/02/09 03:04:35  snw
+#   Add heartbeat
+#
+#
+#
+
+
 use Net::OSCAR;
 use Getopt::Long;
 
@@ -10,6 +29,10 @@ my $botno = 0;
 my $oscar = '';
 my $online = 0;
 my $room = '';
+my %signon = ();
+my $ticks = 0;
+my $heartbeat = time();
+my $hbchk_pending = 0;
 
 sub signon_done
 {
@@ -37,7 +60,15 @@ sub chat_im_in
 sub im_in
 {
     my($oscar, $sender, $message, $is_away) = @_;
-    print "$botsn:  message received from $sender\n";
+    
+    if($message eq "ltping") {
+        $oscar->send_im($sender, "ltpong");     
+    }
+    elsif($message eq "ltpong") {
+        print "$botsn:  heartbeat OK\n";
+        $heartbeat = time();
+        $hbchk_pending = 0;
+    }
 }
 
 sub oscar_error
@@ -45,7 +76,7 @@ sub oscar_error
     my($oscar, $connection, $error, $description, $fatal) = @_;
 
     if($fatal != 0) {
-        print "$botsn:  fatal OSCAR error:  $description\n";        
+        die "$botsn:  fatal OSCAR error:  $description\n";       
     }
     else {
         print "$botsn:  recoverable OSCAR error: $description\n";
@@ -73,8 +104,23 @@ sub simulate_load
             $room->chat_send("//roll-dice15-sides999");
         }
     }
-    sleep 1;
+    $ticks = $ticks + 1;
+
+    if($ticks > 20) {
+        $heartbeat = time();
+        $oscar->send_im($botsn, "ltping");
+        print "$botsn:  heartbeat check\n";
+        $hbchk_pending = 1;
+        $ticks = 0;
+    }
+
+    if($hbchk_pending == 1) {
+        if(time() - $heartbeat > 60) {
+            die "$botsn:  heartbeat check FAILED; bot terminating\n";
+        }
+    }
     
+    sleep 1
 }
 
 sub main
@@ -88,9 +134,9 @@ sub main
                "aimhost=s" => \$botsrv)
         or die("error in command line arguments");
 
-    $botsn = "ldtest$botno";
+    $botsn = "lt$botno\pr$$";
     
-    my %signon = (
+    %signon = (
         screenname => $botsn,
         password => $botpw,
         host => $botsrv,
@@ -112,7 +158,7 @@ sub main
         $oscar->do_one_loop();
         if($online == 1) {
             simulate_load();
-        }
+        }        
     }
 }