Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/A+network+echo+Windows+service+using+TWAPI?V=3
QUERY_STRINGV=3
CONTENT_TYPE
DOCUMENT_URI/revision/A+network+echo+Windows+service+using+TWAPI
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.126.16
REMOTE_PORT27044
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.227.24.209
HTTP_CF_RAY876e22c99bc9e124-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP18.227.24.209
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {A network echo Windows service using TWAPI} {The main network echo server is basically the sample from
the Tcl Developer Xchange [http://www.tcl.tk/about/netserver.html]. Adapted here to run as a
Windows service using [TWAPI].

----

Usage proc to display message and exit on error. Note the same script
is used for installing/uninstalling the service as for running the
service itself.

======
  # A sample Windows service implemented in Tcl using TWAPI's windows
  # services module.
  #

  proc usage {} {
      puts stderr {
  Usage:
       tclsh echoservice.tcl install SERVICENAME
	 -- installs the service as SERVICENAME
       tclsh echoservice.tcl uninstall SERVICENAME
	 -- uninstalls the service
  Then start/stop the service using either "net start" or the services control
  manager GUI.
      }
      exit 1
  }
=======

----

Then standard network echo server from the Xchange, slightly adapted to
explicitly maintain state. When "paused", the server stays running but
does not talk to the clients.

======
  package require twapi

  ################################################################
  # The echo_server code is almost verbatim from the Tcl Developers
  # Exchange samples.

  set echo(server_port) 2008;    # Port the echo server should listen on
  set echo(state) stopped;       # State of the server

  # echo_server --
  #       Open the server listening socket
  #       and enter the Tcl event loop
  #
  # Arguments:
  #       port    The server's port number

  proc echo_server {} {
      global echo
      set echo(server_socket) [socket -server echo_accept $echo(server_port)]
  }

  # echo_accept --
  #       Accept a connection from a new client.
  #       This is called after a new socket connection
  #       has been created by Tcl.
  #
  # Arguments:
  #       sock    The new socket connection to the client
  #       addr    The client's IP address
  #       port    The client's port number

  proc echo_accept {sock addr port} {
      global echo

      if {$echo(server_state) ne "running"} {
	  close $sock
	  return
      }

      # Record the client's information

      set echo(addr,$sock) [list $addr $port $sock]

      # Ensure that each "puts" by the server
      # results in a network transmission

      fconfigure $sock -buffering line

      # Set up a callback for when the client sends data

      fileevent $sock readable [list echo $sock]
  }

  # echo --
  #       This procedure is called when the server
  #       can read data from the client
  #
  # Arguments:
  #       sock    The socket connection to the client

  proc echo {sock} {
      global echo

      # Check end of file or abnormal connection drop,
      # then echo data back to the client.

      if {[eof $sock] || [catch {gets $sock line}]} {
	  close $sock
	  unset -nocomplain echo(addr,$sock)
      } else {
	  puts $sock $line
      }
  }

  #
  # Close all sockets
  proc echo_close_shop {{serveralso true}} {
      global echo

      # Loop and close all client connections
      foreach {index conn} [array get echo addr,*] {
	  close [lindex $conn 2]; # 3rd element is socket handle
	  unset -nocomplain echo($index)
      }

      if {$serveralso} {
	  close $echo(server_socket)
	  unset -nocomplain echo(server_socket)
      }
  }

  #
  # A client of the echo service.
  #

  proc echo_client {host port} {
      set s [socket $host $port]
      fconfigure $s -buffering line
      return $s
  }

  # A sample client session looks like this
  #   set s [echo_client localhost 2540]
  #   puts $s "Hello!"
  #   gets $s line

======

----

The actual Windows-related code itself (the main point of this posting).
Basically, a callback that accepts control codes from the Windows SCM
and changes state appropriately.

======
  ################################################################
  # The actual service related code

  #
  # Update the SCM with our state
  proc report_state {name seq} {
      if {[catch {
	  set ret [twapi::update_service_status $name $seq $::echo(server_state)]
      } msg]} {
	  ::twapi::eventlog_log "Service $name failed to update status: $msg"
      }
  }

  # Callback handler
  proc service_control_handler {control {name ""} {seq 0} args} {
      global echo
      switch -exact -- $control {
	  start {
	      if {[catch {
		  # Start the echo server
		  echo_server
		  set echo(server_state) running
	      } msg]} {
		  twapi::eventlog_log "Could not start echo server: $msg"
	      }
	      report_state $name $seq
	  }
	  stop {
	      echo_close_shop
	      set echo(server_state) stopped
	      report_state $name $seq
	  }
	  pause {
	      # Close all client connections but leave server socket open
	      echo_close_shop false
	      set echo(server_state) paused
	      report_state $name $seq
	  }
	  continue {
	      set echo(server_state) running
	      report_state $name $seq
	  }
	  userdefined {
	      # Note we do not need to call update_service_status
	      set ::done 1;       # Hard exit
	  }
	  all_stopped {
	      # Mark we are all done so we can exit at global level
	      set ::done 1
	  }
	  default {
	      # Ignore
	  }
      }
  }

======

----
And here's where the script actually starts running, parse arguments,
and then depending on the option, either install/uninstall the service,
or run as a service.

======

  ################################################################
  # Main code

  # Parse arguments
  if {[llength $argv] != 2} {
      usage
  }

  set service_name [lindex $argv 1]
  switch -exact -- [lindex $argv 0] {
      service {
	  # We are running as a service
	  if {[catch {
	      twapi::run_as_service [list [list $service_name ::service_control_handler]]
	  } msg]} {
	      twapi::eventlog_log "Service error: $msg"
	  }
	  # We sit in the event loop until service control stop us through
	  # the event handler
	  vwait ::done
      }
      install {
	  if {[twapi::service_exists $service_name]} {
	      puts stderr "Service $service_name already exists"
	      exit 1
	  }

	  # Make the names a short name to not have to deal with
	  # quoting of spaces in the path

	  set exe [file nativename [file attributes [info nameofexecutable] -shortname]]
	  set script [file nativename [file attributes [file normalize [info script]] -shortname]]
	  twapi::create_service $service_name "$exe $script service $service_name"
      }
      uninstall {
	  if {[twapi::service_exists $service_name]} {
	      twapi::delete_service $service_name
	  }
      }
      default {
	  usage
      }
  }

  exit 0
======

----
!!!!!!
%| enter categories here |%
!!!!!!} regexp2} CALL {my render {A network echo Windows service using TWAPI} {The main network echo server is basically the sample from
the Tcl Developer Xchange [http://www.tcl.tk/about/netserver.html]. Adapted here to run as a
Windows service using [TWAPI].

----

Usage proc to display message and exit on error. Note the same script
is used for installing/uninstalling the service as for running the
service itself.

======
  # A sample Windows service implemented in Tcl using TWAPI's windows
  # services module.
  #

  proc usage {} {
      puts stderr {
  Usage:
       tclsh echoservice.tcl install SERVICENAME
	 -- installs the service as SERVICENAME
       tclsh echoservice.tcl uninstall SERVICENAME
	 -- uninstalls the service
  Then start/stop the service using either "net start" or the services control
  manager GUI.
      }
      exit 1
  }
=======

----

Then standard network echo server from the Xchange, slightly adapted to
explicitly maintain state. When "paused", the server stays running but
does not talk to the clients.

======
  package require twapi

  ################################################################
  # The echo_server code is almost verbatim from the Tcl Developers
  # Exchange samples.

  set echo(server_port) 2008;    # Port the echo server should listen on
  set echo(state) stopped;       # State of the server

  # echo_server --
  #       Open the server listening socket
  #       and enter the Tcl event loop
  #
  # Arguments:
  #       port    The server's port number

  proc echo_server {} {
      global echo
      set echo(server_socket) [socket -server echo_accept $echo(server_port)]
  }

  # echo_accept --
  #       Accept a connection from a new client.
  #       This is called after a new socket connection
  #       has been created by Tcl.
  #
  # Arguments:
  #       sock    The new socket connection to the client
  #       addr    The client's IP address
  #       port    The client's port number

  proc echo_accept {sock addr port} {
      global echo

      if {$echo(server_state) ne "running"} {
	  close $sock
	  return
      }

      # Record the client's information

      set echo(addr,$sock) [list $addr $port $sock]

      # Ensure that each "puts" by the server
      # results in a network transmission

      fconfigure $sock -buffering line

      # Set up a callback for when the client sends data

      fileevent $sock readable [list echo $sock]
  }

  # echo --
  #       This procedure is called when the server
  #       can read data from the client
  #
  # Arguments:
  #       sock    The socket connection to the client

  proc echo {sock} {
      global echo

      # Check end of file or abnormal connection drop,
      # then echo data back to the client.

      if {[eof $sock] || [catch {gets $sock line}]} {
	  close $sock
	  unset -nocomplain echo(addr,$sock)
      } else {
	  puts $sock $line
      }
  }

  #
  # Close all sockets
  proc echo_close_shop {{serveralso true}} {
      global echo

      # Loop and close all client connections
      foreach {index conn} [array get echo addr,*] {
	  close [lindex $conn 2]; # 3rd element is socket handle
	  unset -nocomplain echo($index)
      }

      if {$serveralso} {
	  close $echo(server_socket)
	  unset -nocomplain echo(server_socket)
      }
  }

  #
  # A client of the echo service.
  #

  proc echo_client {host port} {
      set s [socket $host $port]
      fconfigure $s -buffering line
      return $s
  }

  # A sample client session looks like this
  #   set s [echo_client localhost 2540]
  #   puts $s "Hello!"
  #   gets $s line

======

----

The actual Windows-related code itself (the main point of this posting).
Basically, a callback that accepts control codes from the Windows SCM
and changes state appropriately.

======
  ################################################################
  # The actual service related code

  #
  # Update the SCM with our state
  proc report_state {name seq} {
      if {[catch {
	  set ret [twapi::update_service_status $name $seq $::echo(server_state)]
      } msg]} {
	  ::twapi::eventlog_log "Service $name failed to update status: $msg"
      }
  }

  # Callback handler
  proc service_control_handler {control {name ""} {seq 0} args} {
      global echo
      switch -exact -- $control {
	  start {
	      if {[catch {
		  # Start the echo server
		  echo_server
		  set echo(server_state) running
	      } msg]} {
		  twapi::eventlog_log "Could not start echo server: $msg"
	      }
	      report_state $name $seq
	  }
	  stop {
	      echo_close_shop
	      set echo(server_state) stopped
	      report_state $name $seq
	  }
	  pause {
	      # Close all client connections but leave server socket open
	      echo_close_shop false
	      set echo(server_state) paused
	      report_state $name $seq
	  }
	  continue {
	      set echo(server_state) running
	      report_state $name $seq
	  }
	  userdefined {
	      # Note we do not need to call update_service_status
	      set ::done 1;       # Hard exit
	  }
	  all_stopped {
	      # Mark we are all done so we can exit at global level
	      set ::done 1
	  }
	  default {
	      # Ignore
	  }
      }
  }

======

----
And here's where the script actually starts running, parse arguments,
and then depending on the option, either install/uninstall the service,
or run as a service.

======

  ################################################################
  # Main code

  # Parse arguments
  if {[llength $argv] != 2} {
      usage
  }

  set service_name [lindex $argv 1]
  switch -exact -- [lindex $argv 0] {
      service {
	  # We are running as a service
	  if {[catch {
	      twapi::run_as_service [list [list $service_name ::service_control_handler]]
	  } msg]} {
	      twapi::eventlog_log "Service error: $msg"
	  }
	  # We sit in the event loop until service control stop us through
	  # the event handler
	  vwait ::done
      }
      install {
	  if {[twapi::service_exists $service_name]} {
	      puts stderr "Service $service_name already exists"
	      exit 1
	  }

	  # Make the names a short name to not have to deal with
	  # quoting of spaces in the path

	  set exe [file nativename [file attributes [info nameofexecutable] -shortname]]
	  set script [file nativename [file attributes [file normalize [info script]] -shortname]]
	  twapi::create_service $service_name "$exe $script service $service_name"
      }
      uninstall {
	  if {[twapi::service_exists $service_name]} {
	      twapi::delete_service $service_name
	  }
      }
      default {
	  usage
      }
  }

  exit 0
======

----
!!!!!!
%| enter categories here |%
!!!!!!}} CALL {my revision {A network echo Windows service using TWAPI}} CALL {::oo::Obj4040690 process revision/A+network+echo+Windows+service+using+TWAPI} CALL {::oo::Obj4040688 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4