Class: Win32::Daemon

Inherits:
Object
  • Object
show all
Extended by:
Windows::Functions, Windows::Structs
Includes:
Windows::Constants, Windows::Functions, Windows::Structs
Defined in:
lib/win32/daemon.rb

Overview

The Daemon class

Constant Summary collapse

VERSION =

The version of this library

'0.8.0'

Constants included from Windows::Constants

Windows::Constants::DELETE, Windows::Constants::ERROR_FILE_NOT_FOUND, Windows::Constants::ERROR_INSUFFICIENT_BUFFER, Windows::Constants::ERROR_MORE_DATA, Windows::Constants::FORMAT_MESSAGE_FROM_SYSTEM, Windows::Constants::FORMAT_MESSAGE_IGNORE_INSERTS, Windows::Constants::IDLE_CONTROL_CODE, Windows::Constants::INFINITE, Windows::Constants::NO_ERROR, Windows::Constants::SC_ACTION_NONE, Windows::Constants::SC_ACTION_REBOOT, Windows::Constants::SC_ACTION_RESTART, Windows::Constants::SC_ACTION_RUN_COMMAND, Windows::Constants::SC_ENUM_PROCESS_INFO, Windows::Constants::SC_MANAGER_ALL_ACCESS, Windows::Constants::SC_MANAGER_CONNECT, Windows::Constants::SC_MANAGER_CREATE_SERVICE, Windows::Constants::SC_MANAGER_ENUMERATE_SERVICE, Windows::Constants::SC_MANAGER_LOCK, Windows::Constants::SC_MANAGER_MODIFY_BOOT_CONFIG, Windows::Constants::SC_MANAGER_QUERY_LOCK_STATUS, Windows::Constants::SC_STATUS_PROCESS_INFO, Windows::Constants::SERVICE_ACCEPT_HARDWAREPROFILECHANGE, Windows::Constants::SERVICE_ACCEPT_NETBINDCHANGE, Windows::Constants::SERVICE_ACCEPT_PARAMCHANGE, Windows::Constants::SERVICE_ACCEPT_PAUSE_CONTINUE, Windows::Constants::SERVICE_ACCEPT_POWEREVENT, Windows::Constants::SERVICE_ACCEPT_PRESHUTDOWN, Windows::Constants::SERVICE_ACCEPT_SESSIONCHANGE, Windows::Constants::SERVICE_ACCEPT_SHUTDOWN, Windows::Constants::SERVICE_ACCEPT_STOP, Windows::Constants::SERVICE_ACCEPT_TIMECHANGE, Windows::Constants::SERVICE_ACCEPT_TRIGGEREVENT, Windows::Constants::SERVICE_ACTIVE, Windows::Constants::SERVICE_ADAPTER, Windows::Constants::SERVICE_ALL_ACCESS, Windows::Constants::SERVICE_AUTO_START, Windows::Constants::SERVICE_BOOT_START, Windows::Constants::SERVICE_CHANGE_CONFIG, Windows::Constants::SERVICE_CONFIG_DELAYED_AUTO_START_INFO, Windows::Constants::SERVICE_CONFIG_DESCRIPTION, Windows::Constants::SERVICE_CONFIG_FAILURE_ACTIONS, Windows::Constants::SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, Windows::Constants::SERVICE_CONFIG_PRESHUTDOWN_INFO, Windows::Constants::SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, Windows::Constants::SERVICE_CONFIG_SERVICE_SID_INFO, Windows::Constants::SERVICE_CONTINUE_PENDING, Windows::Constants::SERVICE_CONTROL_CONTINUE, Windows::Constants::SERVICE_CONTROL_DEVICEEVENT, Windows::Constants::SERVICE_CONTROL_HARDWAREPROFILECHANGE, Windows::Constants::SERVICE_CONTROL_INTERROGATE, Windows::Constants::SERVICE_CONTROL_NETBINDADD, Windows::Constants::SERVICE_CONTROL_NETBINDDISABLE, Windows::Constants::SERVICE_CONTROL_NETBINDENABLE, Windows::Constants::SERVICE_CONTROL_NETBINDREMOVE, Windows::Constants::SERVICE_CONTROL_PARAMCHANGE, Windows::Constants::SERVICE_CONTROL_PAUSE, Windows::Constants::SERVICE_CONTROL_POWEREVENT, Windows::Constants::SERVICE_CONTROL_PRESHUTDOWN, Windows::Constants::SERVICE_CONTROL_SESSIONCHANGE, Windows::Constants::SERVICE_CONTROL_SHUTDOWN, Windows::Constants::SERVICE_CONTROL_STOP, Windows::Constants::SERVICE_CONTROL_TIMECHANGE, Windows::Constants::SERVICE_CONTROL_TRIGGEREVENT, Windows::Constants::SERVICE_DEMAND_START, Windows::Constants::SERVICE_DISABLED, Windows::Constants::SERVICE_DRIVER, Windows::Constants::SERVICE_ENUMERATE_DEPENDENTS, Windows::Constants::SERVICE_ERROR_CRITICAL, Windows::Constants::SERVICE_ERROR_IGNORE, Windows::Constants::SERVICE_ERROR_NORMAL, Windows::Constants::SERVICE_ERROR_SEVERE, Windows::Constants::SERVICE_FILE_SYSTEM_DRIVER, Windows::Constants::SERVICE_INACTIVE, Windows::Constants::SERVICE_INTERACTIVE_PROCESS, Windows::Constants::SERVICE_INTERROGATE, Windows::Constants::SERVICE_KERNEL_DRIVER, Windows::Constants::SERVICE_NO_CHANGE, Windows::Constants::SERVICE_PAUSED, Windows::Constants::SERVICE_PAUSE_CONTINUE, Windows::Constants::SERVICE_PAUSE_PENDING, Windows::Constants::SERVICE_QUERY_CONFIG, Windows::Constants::SERVICE_QUERY_STATUS, Windows::Constants::SERVICE_RECOGNIZER_DRIVER, Windows::Constants::SERVICE_RUNNING, Windows::Constants::SERVICE_START, Windows::Constants::SERVICE_START_PENDING, Windows::Constants::SERVICE_STATE_ALL, Windows::Constants::SERVICE_STOP, Windows::Constants::SERVICE_STOPPED, Windows::Constants::SERVICE_STOP_PENDING, Windows::Constants::SERVICE_SYSTEM_START, Windows::Constants::SERVICE_TYPE_ALL, Windows::Constants::SERVICE_USER_DEFINED_CONTROL, Windows::Constants::SERVICE_WIN32, Windows::Constants::SERVICE_WIN32_OWN_PROCESS, Windows::Constants::SERVICE_WIN32_SHARE_PROCESS, Windows::Constants::WAIT_FAILED, Windows::Constants::WAIT_OBJECT_0, Windows::Constants::WAIT_TIMEOUT

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.mainloopObject

This is a shortcut for Daemon.new + Daemon#mainloop.



201
202
203
# File 'lib/win32/daemon.rb', line 201

def self.mainloop
  self.new.mainloop
end

Instance Method Details

#mainloopObject

This is the method that actually puts your code into a loop and allows it to run as a service. The code that is actually run while in the mainloop is what you defined in your own Daemon#service_main method.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/win32/daemon.rb', line 209

def mainloop
  @@waiting_control_code = IDLE_CONTROL_CODE
  @@dwServiceState = 0

  # Redirect STDIN, STDOUT and STDERR to the NUL device if they're still
  # associated with a tty. This helps newbs avoid Errno::EBADF errors.
  STDIN.reopen('NUL') if STDIN.isatty
  STDOUT.reopen('NUL') if STDOUT.isatty
  STDERR.reopen('NUL') if STDERR.isatty

  # Calling init here so that init failures never even tries to start the
  # service. Of course that means that init methods must be very quick
  # because the SCM will be receiving no START_PENDING messages while
  # init's running.
  #
  # TODO: Fix?
  service_init() if respond_to?('service_init')

  # Create the event to signal the service to start.
  @@hStartEvent = CreateEvent(nil, true, false, nil)

  if @@hStartEvent == 0
    raise SystemCallError.new('CreateEvent', FFI.errno)
  end

  # Create the event to signal the service to stop.
  @@hStopEvent = CreateEvent(nil, true, false, nil)

  if @@hStopEvent == 0
    raise SystemCallError.new('CreateEvent', FFI.errno)
  end

  # Create the event to signal the service that stop has completed
  @@hStopCompletedEvent = CreateEvent(nil, true, false, nil)

  if @@hStopCompletedEvent == 0
    raise SystemCallError.new('CreateEvent', FFI.errno)
  end

  hThread = CreateThread(nil, 0, ThreadProc, nil, 0, nil)

  if hThread == 0
    raise SystemCallError.new('CreateThread', FFI.errno)
  end

  events = FFI::MemoryPointer.new(:pointer, FFI::Pointer.size*2)
  events.put_pointer(0, FFI::Pointer.new(hThread))
  events.put_pointer(FFI::Pointer.size, FFI::Pointer.new(@@hStartEvent))

  while ((index = WaitForMultipleObjects(2, events, false, 1000)) == WAIT_TIMEOUT) do
  end

  if index == WAIT_FAILED
    raise SystemCallError.new('WaitForMultipleObjects', FFI.errno)
  end

  # The thread exited, so the show is off.
  if index == WAIT_OBJECT_0
    raise "Service_Main thread exited abnormally"
  end

  thr = Thread.new do
    while(WaitForSingleObject(@@hStopEvent, 10) == WAIT_TIMEOUT)
      # Check to see if anything interesting has been signaled
      case @@waiting_control_code
        when SERVICE_CONTROL_PAUSE
          service_pause() if respond_to?('service_pause')
        when SERVICE_CONTROL_CONTINUE
          service_resume() if respond_to?('service_resume')
        when SERVICE_CONTROL_INTERROGATE
          service_interrogate() if respond_to?('service_interrogate')
        when SERVICE_CONTROL_SHUTDOWN
          service_shutdown() if respond_to?('service_shutdown')
        when SERVICE_CONTROL_PARAMCHANGE
          service_paramchange() if respond_to?('service_paramchange')
        when SERVICE_CONTROL_NETBINDADD
          service_netbindadd() if respond_to?('service_netbindadd')
        when SERVICE_CONTROL_NETBINDREMOVE
          service_netbindremove() if respond_to?('service_netbindremove')
        when SERVICE_CONTROL_NETBINDENABLE
          service_netbindenable() if respond_to?('service_netbindenable')
        when SERVICE_CONTROL_NETBINDDISABLE
          service_netbinddisable() if respond_to?('service_netbinddisable')
      end
      @@waiting_control_code = IDLE_CONTROL_CODE
    end

    service_stop() if respond_to?('service_stop')
  end

  if respond_to?('service_main')
    service_main(*@@Argv)
  end

  thr.join
end

#running?Boolean

Returns whether or not the service is in a running state, i.e. the service status is either RUNNING, PAUSED or IDLE.

This is typically used within your service_main method to setup the main loop. For example:

class MyDaemon < Daemon
   def service_main
      while running?
         # Your main loop here
      end
   end
end

Returns:

  • (Boolean)


341
342
343
# File 'lib/win32/daemon.rb', line 341

def running?
  [SERVICE_RUNNING, SERVICE_PAUSED, 0].include?(@@dwServiceState)
end

#stateObject

Returns the state of the service (as an constant integer) which can be any of the service status constants, e.g. RUNNING, PAUSED, etc.

This method is typically used within your service_main method to setup the loop. For example:

class MyDaemon < Daemon
  def service_main
    while state == RUNNING || state == PAUSED || state == IDLE
      # Your main loop here
    end
  end
end

See the Daemon#running? method for an abstraction of the above code.



322
323
324
# File 'lib/win32/daemon.rb', line 322

def state
  @@dwServiceState
end