Implemented parts of the server and protocol handler.
git-svn-id: svn+ssh://svn.luon.net/svn/ildus/trunk@3 65a33f86-aa00-0410-91be-cd1bf5efb309
This commit is contained in:
parent
cb0cf672bd
commit
50062f3b9f
|
@ -8,23 +8,65 @@
|
|||
# any later version.
|
||||
|
||||
require 'gserver'
|
||||
require 'yaml'
|
||||
|
||||
require 'ildus/server/handler'
|
||||
|
||||
module Ildus
|
||||
|
||||
class Server < GServer
|
||||
|
||||
# The interface to listen specified default by the hostname.
|
||||
DEFAULT_HOST = '::'
|
||||
|
||||
# The maximal number of connections.
|
||||
MAX_CONNECTIONS = 20
|
||||
|
||||
# The server configuration.
|
||||
attr_reader :config
|
||||
|
||||
# Create a Ildus server instance that is a derivate of a generic
|
||||
# server. Accepts an alternative _config_file_ as optional argument.
|
||||
def initialize(config_file=nil)
|
||||
@config = nil
|
||||
parse_config(config_file)
|
||||
|
||||
super(config['port'], DEFAULT_HOST, 20, $stderr, true, false)
|
||||
end
|
||||
|
||||
def serve(io)
|
||||
hdl = Handler.new(self, io)
|
||||
hdl.handle_client
|
||||
rescue => e
|
||||
$stderr.puts "#{e.class}: #{e}"
|
||||
$stderr.puts e.backtrace
|
||||
end
|
||||
|
||||
# Start the Ildus server.
|
||||
def start
|
||||
super
|
||||
join
|
||||
end
|
||||
|
||||
# Stop and shutdown the Ildus server. An _status_ code (defaults to 0)
|
||||
# can be used as an optional argument.
|
||||
def shutdown(status=0)
|
||||
super()
|
||||
exit(status)
|
||||
end
|
||||
|
||||
#########
|
||||
private
|
||||
#########
|
||||
|
||||
# Parses the configuration file _filename_ and stores the parsed
|
||||
# contents.
|
||||
def parse_config(filename)
|
||||
raise ArgumentError unless FileTest.exists? filename
|
||||
|
||||
File.open(filename, "r") do |io|
|
||||
@config = YAML.load(io)
|
||||
end
|
||||
end
|
||||
|
||||
end # class Server
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
# = ildus/server/handler - Ildus server command handler
|
||||
#
|
||||
# Copyright (C) 2005 Paul van Tilburg <paul@luon.net>
|
||||
#
|
||||
# Ildus is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
|
||||
module Ildus
|
||||
|
||||
class Server < GServer
|
||||
|
||||
class Handler
|
||||
|
||||
class ProtocolException < StandardError; end
|
||||
class CmdUnknownError < ProtocolException; end
|
||||
class ArgsSyntaxError < ProtocolException; end
|
||||
class NotImplementedError < ProtocolException; end
|
||||
class AlreadyAuthError < ProtocolException; end
|
||||
class TooManyUnknownError < ProtocolException; end
|
||||
|
||||
MaxCmdErrs = 3
|
||||
|
||||
ProtocolCodeMapping = {
|
||||
200 => "Command OK.",
|
||||
# 210, 211, 212, 213
|
||||
214 => "Direct comments to %s.",
|
||||
215 => "Listing done.",
|
||||
220 => "%s %s %s %s, welcome.",
|
||||
221 => "%s closed connection, goodbye!",
|
||||
230 => "User %s authenticated, proceed.",
|
||||
240 => "Updated host %s to IP %s.",
|
||||
# 330
|
||||
331 => "User name OK, need password.",
|
||||
# 420
|
||||
421 => "%s forcibly closed connection.",
|
||||
422 => "connection timed out, %s forcibly closed connection.",
|
||||
# 423, 424
|
||||
425 => "Can't find host %s.",
|
||||
426 => "Can't find %s-record of host %s.",
|
||||
500 => "Syntax error, command `%s' unrecognized.",
|
||||
501 => "Syntax error in arguments.",
|
||||
502 => "Command not implemented.",
|
||||
503 => "Too many unrecognized commands!",
|
||||
504 => "You are already authenticated!",
|
||||
505 => "Server error: %s!",
|
||||
506 => "Server error, update failed: %s",
|
||||
530 => "Not authenticated!"
|
||||
}
|
||||
|
||||
def intialize(server, io)
|
||||
@server = server
|
||||
@io = io
|
||||
end
|
||||
|
||||
def handle_client
|
||||
io.puts prot_msg(220, "localhost", Program, Version, Time.now.to_s)
|
||||
|
||||
cmd_errs = 0
|
||||
io.each_line do |line|
|
||||
begin
|
||||
cmd, *args = line.split /\s+/
|
||||
handle_command(io, cmd, args)
|
||||
rescue CmdUnknownError # 500
|
||||
raise TooManyUnknownError if cmd_errs > MaxCmdErrs
|
||||
io.puts prot_msg(500, cmd)
|
||||
cmd_errs = cmd_errs + 1
|
||||
rescue ArgsSyntaxError # 501
|
||||
io.puts prot_msg(501)
|
||||
rescue NotImplementedError # 502
|
||||
io.puts prot_msg(502)
|
||||
rescue AlreadyAuthError # 504
|
||||
io.puts prot_msg(504)
|
||||
end
|
||||
end
|
||||
rescue TooManyUnknownError # 503
|
||||
io.puts prot_msg(503)
|
||||
rescue RuntimeError => msg # 505
|
||||
io.puts prot_msg(505, msg)
|
||||
raise
|
||||
end
|
||||
|
||||
#########
|
||||
private
|
||||
#########
|
||||
|
||||
def handle_command(io, cmd, args)
|
||||
method_name = cmd.downcase + "_cmd"
|
||||
meth = method(method_name)
|
||||
meth.call(*args)
|
||||
rescue NameError
|
||||
raise CmdUnknownError
|
||||
end
|
||||
|
||||
def prot_msg(code, *args)
|
||||
code.to_s << " " << ProtocolCodeMapping[code] % args
|
||||
end
|
||||
|
||||
end # class Handler
|
||||
|
||||
end # class Server
|
||||
|
||||
end # module Ildus
|
Reference in New Issue