getting integer value for win32 daemon state in windows and not getting current status

Viewed 128

I want to create and install a service which should run in background until it should not pause or stop from services.

So I created the following test script :

use Win32::Daemon;

my $ServicePath = 'C:\Strawberry\perl\bin\perl.exe';
my $ServiceParams = 'C:\ila\bin\ilad.pl';

my %service_info = (
    name    => 'ilad',
    display => 'intelligent Lightweight Agent (ilad)',
    path    => $ServicePath,
    description => 'ilad',
    parameters => $ServiceParams,
    service_type => SERVICE_WIN32_OWN_PROCESS,
    start_type => SERVICE_AUTO_START);

## create ilad service ##

if(Win32::Daemon::CreateService( \%service_info))
{
    print "successfully added \n";
}
else
{
    print "failed to add service: " . Win32::FormatMessage( Win32::Daemon::GetLastError()); 
}

# Tell the OS to start processing the service...
Win32::Daemon::StartService(\%service_info))

print "Waiting...\n";
# Wait until the service manager is ready for us to continue...

print "SERVICE_NOT_READY " . SERVICE_NOT_READY . "\n";
print "SERVICE_STOPPED " . SERVICE_STOPPED . "\n";
print "SERVICE_RUNNING " . SERVICE_RUNNING . "\n";
print "SERVICE_PAUSED " . SERVICE_PAUSED . "\n";
print "SERVICE_START_PENDING " . SERVICE_START_PENDING . "\n";
print "SERVICE_STOP_PENDING " . SERVICE_STOP_PENDING . "\n";
print "SERVICE_CONTINUE_PENDING " . SERVICE_CONTINUE_PENDING . "\n";
print "SERVICE_PAUSE_PENDING " . SERVICE_PAUSE_PENDING . "\n";

while( SERVICE_START_PENDING != Win32::Daemon::State() )
{
    sleep( 1 );
    print Win32::Daemon::State() . "\n";
}
print "Running...\n";
# Now let the service manager know that we are running...
Win32::Daemon::State( SERVICE_RUNNING );

# Okay, go ahead and process stuff...
unlink( glob( "c:\\temp\\*.tmp" ) );

# Tell the OS that the service is terminating...
Win32::Daemon::StopService();

and I have this:

successfully added  
Waiting...  
SERVICE_NOT_READY 0  
SERVICE_STOPPED 1  
SERVICE_RUNNING 4  
SERVICE_PAUSED 7  
SERVICE_START_PENDING 2  
SERVICE_STOP_PENDING 3  
SERVICE_CONTINUE_PENDING 5  
SERVICE_PAUSE_PENDING 6  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
1  
1  
1  
1  
1  
1  
Terminating on signal SIGINT(2)  

So it never reaches the SERVICE_RUNNING state and getting integer value and not getting current status of service.

I am using Strawberry perl. So anyone is having any idea?

1 Answers

Contrary to what you think, the service does get run. The problem is that you're not looking at the output of the service.

You're executing code that should only be executed by the service (StartService) in your command-line script. This is wrong.

You're executing code that creates the service (CreateService) inside the service. This makes no sense.

Fixed:

use 5.014;
use warnings;

use FindBin qw( $RealBin $RealScript );
use Win32::Daemon;

my $log_qfn = "C:\\Users\\ikegami\\a.log";
my $service_name = 'testtest';

sub logit {
   my ($msg) = @_;
   chomp($msg);

   open(my $fh, ">>", $log_qfn)
      or warn("Can't append to logit \"$log_qfn\": $!\n"), return;

   say $fh "[$$] $msg";
}

sub install_service {
   my %service_info = (
      name        => $service_name,
      display     => 'TESTTEST',
      description => 'TESTTESTTEST',
      path        => $^X,
      parameters  => qq{"$RealBin/$RealScript" service},
   );

   if (Win32::Daemon::CreateService(\%service_info)) {
      say "Successfully added.";
   } else {
      print "Failed to add service: " . Win32::FormatMessage( Win32::Daemon::GetLastError()); 
   }
}


sub uninstall_service {
   if (Win32::Daemon::DeleteService("", $service_name)) {
      say "Successfully removed.";
   } else {
      print "Failed to remove service: " . Win32::FormatMessage( Win32::Daemon::GetLastError()); 
   }
}


sub start_service {
   system("net", "start", "testtest");
}


sub service {
   logit("SERVICE_NOT_READY "        . SERVICE_NOT_READY);
   logit("SERVICE_STOPPED "          . SERVICE_STOPPED);
   logit("SERVICE_RUNNING "          . SERVICE_RUNNING);
   logit("SERVICE_PAUSED "           . SERVICE_PAUSED);
   logit("SERVICE_START_PENDING "    . SERVICE_START_PENDING);
   logit("SERVICE_STOP_PENDING "     . SERVICE_STOP_PENDING);
   logit("SERVICE_CONTINUE_PENDING " . SERVICE_CONTINUE_PENDING);
   logit("SERVICE_PAUSE_PENDING "    . SERVICE_PAUSE_PENDING);

   logit("state = " . Win32::Daemon::State());

   Win32::Daemon::StartService();

   logit("Waiting");
   while (1) {
      my $state = Win32::Daemon::State();
      logit("state = $state");
      last if $state == SERVICE_START_PENDING;
      sleep(1);
   }

   logit("Running");
   Win32::Daemon::State( SERVICE_RUNNING );
   logit("state = " . Win32::Daemon::State());

   logit("This is the service doing stuff.");

   logit("Stopping");
   Win32::Daemon::StopService();
   logit("state = " . Win32::Daemon::State());
}


{
   @ARGV == 1
      or die("usage\n");

   my $cmd = shift(@ARGV);
   logit($cmd);
   if    ( $cmd eq 'install'   ) { install_service();   }
   elsif ( $cmd eq 'uninstall' ) { uninstall_service(); }
   elsif ( $cmd eq 'start'     ) { start_service();     }
   elsif ( $cmd eq 'service'   ) { service();           }
   else {
      die("usage\n");
   }
}

Output:

C:\Users\ikegami>a.pl install
Successfully added.

C:\Users\ikegami>type a.log
[40952] install

C:\Users\ikegami>wmic Service WHERE Name="testtest" GET Name, PathName
Name      PathName
testtest  C:\progs\sp5302-x64\perl\bin\perl.exe "C:/Users/ikegami\a.pl" service

C:\Users\ikegami>a.pl start
The TESTTEST service is starting..
The TESTTEST service could not be started.

The service did not report an error.

More help is available by typing NET HELPMSG 3534.


C:\Users\ikegami>type a.log
[40952] install
[28480] start
[39880] service
[39880] SERVICE_NOT_READY 0
[39880] SERVICE_STOPPED 1
[39880] SERVICE_RUNNING 4
[39880] SERVICE_PAUSED 7
[39880] SERVICE_START_PENDING 2
[39880] SERVICE_STOP_PENDING 3
[39880] SERVICE_CONTINUE_PENDING 5
[39880] SERVICE_PAUSE_PENDING 6
[39880] state = 0
[39880] Waiting
[39880] state = 0
[39880] state = 2
[39880] Running
[39880] state = 4
[39880] This is the service doing stuff.
[39880] Stopping
[39880] state = 1

C:\Users\ikegami>a.pl uninstall
Successfully removed.

I know it net start says the service wasn't started, but the log clearly shows it was, so ignore that message. The service (intentionally) stopped so soon after starting that net start didn't notice or presumes a failure.

A lot of improvements can be made.

  • Logging messages to the event viewer instead of some arbitrary log file.
  • Cleanly stop the service on exception.
  • Using callbacks as shown in Example 5 of the documentation.
  • Find some way of starting the service without using net start. Maybe Win32::Daemon is capable of that. If so, use that. If not, add support to it!
Related