1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
# A sample implementation of a time service daemon
# We define a subclass of socket (timedaemon)
# that listens on a specified port for incoming connections.
# Once a connection has been estabilished it creates
# a timeserversocket object that serves
# the client by responding to two commands:
# "time" that returns the current local time
# "date" that returns the current date
# Any other request is treated as an error and reported
# to the client with a warning message.
# The socket will serve a maximum of 5 valid client requests and
# then will disconnect and self-destroy, unless the client did it
# before.
# The socket will allow 3 consecutive invalid requests
# after that it will disconnect and self-destroy.
# To run this file drag it from the directory browser to
# the commandline input window, or use /PARSE filename.
# Define the server socket first
# (if it has not been already defined)
# This one starts already connected
# since the parent will call $accept on this socket.
if(!$classDefined(timeserversocket))
{
class(timeserversocket,socket)
{
function(constructor)
{
# The base class is builtin, no need to call base constructor
$this->%consecErrors = 0
$this->%servedRequests = 0
# Indicate success
setreturn 1
}
event(OnDataReceived)
{
# Process the requests
switch($2-)
{
case("time")
{
$this->$write("$time$cr$lf")
$this->%consecErrors = 0
$this->%servedRequests ++
}
case("date")
{
$this->$write("$date$cr$lf")
$this->%consecErrors = 0
$this->%servedRequests ++
}
default:
{
echo TIMESERVERSOCKET: invalid request from client $this->$host() on port $this->$port(): $2-
$this->$write("Invalid request ($2-): valid requests are \"time\" and \"date\"$cr$lf")
$this->%consecErrors ++
if($this->%consecErrors == 3)
{
echo TIMESERVERSOCKET: too many consecutive errors for client $this->$host() on port $this->$port(): disconnecting
$this->$dieNow("Too many errors (3). Goodbye!")
}
}
}
if($this->%servedRequests == 5)$this->$dieNow("Maximum of requests reached (5). Goodbye!")
}
event(OnDisconnect)
{
# The client has closed the connection; die silently
destroy $this
}
function(dieNow)
{
$this->$write($1-)
# Close is not strictly necessary since we will destroy the object
# and the socket class will do it automatically...
$this->$close()
destroy $this
}
}
}
# Parent class: this one listens on the specified port
# for incoming connections.
# Once a connection arrives, it creates a server socket
# and calls $accept on it
if(!$classDefined(timedaemon))
{
class(timedaemon,socket)
{
function(constructor)
{
# The base class is builtin, no need to call base constructor.
# Auto-listen on a specified port.
if(!$isNumber("$1"))
{
# No port number specified. Just refuse to work and die
echo TIMEDAEMON: missing port number in constructor
# Failed
setreturn 0
halt
}
if(!$this->$listen(default,$1))
{
# Listen failed
echo TIMEDAEMON: failed to listen on port $1
echo TIMEDAEMON: error: $this->$lastError()
# Failed
setreturn 0
} else {
# Success
echo TIMEDAEMON: listening on port $1
setreturn 1
}
}
event(OnIncomingConnection)
{
%o = $new(timeserversocket,$this,yahoo)
if(!%o->$accept($this))
{
echo TIMEDAEMON: accept failed: %o->$lastError()
destroy %o
} else {
echo TIMEDAEMON: serving %o->$host() on port %o->$port()
}
}
}
}
# Now let's create a daemon instance
%TimeDaemon = $new(timedaemon,$root,timedaemon,5555)
echo TIMED: service started
echo To test this service you can telnet to localhost on port 5555
echo To stop the service use /destroy \%TimeDaemon
echo Have fun!
# Yup, the service should be up and running now
# If you want to test it just type the following in the commandline
# %Test = $new(socket,$root,testobj)
# %Test->$connect(127.0.0.1,5555)
# %Test->$write("time$cr$lf")
# %Test->$write("date$cr$lf")
# %Test->$close()
# and so on :)
# To kill the service call "destroy %TimeDaemon"
#
# Here are a few common commands and output from a test session
#
# /PARSE /usr/share/doc/kvirc/script-examples/timed.kvs
# ...
# [14:10:11] TIMEDAEMON: listening on port 5555
# [14:10:29] TIMEDAEMON: serving 127.0.0.1 on port 1035
# /%T = $new(socket,$root,testsock)
# /%T->$connect(127.0.0.1,5555)
# [14:10:29] SOCKET @3: connected to 127.0.0.1 on port 5555
# /%T->$write("time$cr$lf")
# [14:10:37] SOCKET @3: received data: 14:10:37
# /%T->$write("date$cr$lf")
# [14:10:41] SOCKET @3: received data: Thu Feb 17 2000
# /%T->$write("foo$cr$lf")
# [14:10:44] TIMESERVERSOCKET: invalid request from client 127.0.0.1 on port 1035: foo
# [14:10:44] SOCKET @3: received data: invalid request (foo): valid requests are "time" and "date"
# /%T->$write("gugu$cr$lf")
# [14:10:57] TIMESERVERSOCKET: invalid request from client 127.0.0.1 on port 1035: gugu
# [14:10:57] SOCKET @3: received data: invalid request (gugu): valid requests are "time" and "date"
# /%T->$write("pippo$cr$lf")
# [14:11:00] TIMESERVERSOCKET: invalid request from client 127.0.0.1 on port 1035: pippo
# [14:11:00] TIMESERVERSOCKET: too many consecutive errors for client 127.0.0.1 on port 1035: disconnecting
# [14:11:00] SOCKET @3: received data: invalid request (pippo): valid requests are "time" and "date"
# [14:11:00] SOCKET @3: disconnected from 127.0.0.1: remote end closed connection
# /destroy %T
#
# There can be many alternative implementations of this service
# You can embed it in aliases or system events.
# Add/remove functionality.
# Well, have fun!
|