#!/usr/bin/wish
# vi: set ts=4 sts=4 sw=4:
# C2003 Uwe Klein Habertwedt
# simpler Socket Server mit TCL , gewonnen aus Mfs Socket Server , basiert unter anderem auf
# einigen im Netz und auf dem Wiki gefunden Vorlagen.
# gebraucht wird
# 1. ein Script/Proc das input bearbeitet und antwortet
# es ist nachher wurscht ob das auf stdin liest und auf stdout antwortet.
# wenn man schlau ist hat dieses proc mind 2 argumente : fdin und fdout
# als Kommandozeilen interpreter bekommt es dann stdin und stdout
# als socket bearbeiter 2 mal den socket!
# 2. ein Script/Proc das eine eingehende Verbindung akzeptiert und das Proc
# aus 1 auf diesen Input per "fileevent" ansetzt
# 3. ein "socket -server" starten mit dem Proc aus 2
# 4. kein punkt 4 : ist schon alles fertig
# was es nicht macht: authentifizierung, anzahl verbindungen begrenzen, Input auf Muell pruefen.
# ( man n socket )
# was es macht: lauschen auf tcp port 9999(default)
# Verbindungen annehmen von Clients
# ( man n fileevent, man n fconfigure )
# input solange annehmen bis "msg" als tcl Script komplett ist
# sprich Klammern rund/eckig Quoting balanciert.
# ( man n info )
# und dann im globalen Kontext ausführen
# man n eval, man n namespace
# Sagen ob ausführung OK oder mit Fehler
# ( man n catch )
# und return Wert an den Client zurueckgeben.
# Wenn man es sicherer machen will wurde man z.B.
# das Script in einem separaten (sicheren) Interpreter ausführen lassen
# ( man n interp )
package provide SockServ 1.0
# create a namespace
namespace eval ::sockServ {
variable status
set status(server,started) {}
variable config
set config(port,default) 9999
set config(server,port) 9999
variable msg {}
variable cerr {}
proc create args {
variable status
variable config
foreach {arg val} $args {
set arg [ string trimm left $arg - ]
set config($arg) $val
}
if { "$status(server,started)" == "OK" } {
puts stderr "SockServ allready started!"
return 1;
}
# Create a server socket on port $config(server,port)
# Call proc accept when a client attempts a connection.
if {[catch { socket -server ::sockServ::accept $config(server,port) } cerr]} {
puts stderr "SockServ : cannot create: ServerSocket on Port $config(server,port) ERR: $cerr "
set status(server,started) OK
}
return 0;
}
# accept a call to the server socket
proc accept {sock addr port} {
variable status
variable config
# Setup handler for future communication on client socket
fileevent $sock readable [list ::sockServ::action $sock $sock]
# Note we've accepted a connection (show how get peer info fm socket)
puts stderr "Accepted Connection from [fconfigure $sock -peername]"
# Read client input in lines, disable blocking I/O
fconfigure $sock -buffering line -blocking 0
# Send Acceptance string to client
puts $sock "$addr:$port, You are connected to the Sock Server."
puts -nonewline $sock "it is [ clock format [ clock seconds ]] : \nShoot : "
flush $sock
set status($sock) "ACCEPT"
set status($sock,peer) "[fconfigure $sock -peername]"
}
proc action {fdin fdout} {
variable status
variable config
variable msg
variable cerr
set ret OK
if {[eof $fdin]} {
puts stderr EOF:$fdin
close $fdin
return
}
append msg [ gets $fdin ]
if {[ string equal -nocase "$msg" "exit" ]} {
puts $fdout "goodbye"
flush $fdout
close $fdout
set msg {}
return
}
if { [info complete $msg] } {
if {[ catch {namespace eval :: $msg} ::sockServ::cerr]} {
set ret ERR
}
puts -nonewline $fdout "$ret: $::sockServ::cerr\nShoot : "
set msg {}
} else {
puts -nonewline $fdout "\n > "
}
flush $fdout
}
}
sockServ::create ;# 1234
# end