Commit a84d9d53 authored by Amos Latteier's avatar Amos Latteier

Bring medusa libraries up to date with current medusa stuff. This should...

Bring medusa libraries up to date with current medusa stuff. This should improve FTP Server on win95 problems, bogus DNS IP address problems, potential memory problems, and more. Also included in a little patch of my own to asyncore.py to fail on shutodown sockets in a slightly more friendly way.
parent c3526c9b
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: asynchat.py,v 1.7 1999/04/09 00:37:33 amos Exp $ # $Id: asynchat.py,v 1.8 1999/05/26 02:08:29 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# ====================================================================== # ======================================================================
...@@ -99,7 +99,6 @@ class async_chat (asyncore.dispatcher): ...@@ -99,7 +99,6 @@ class async_chat (asyncore.dispatcher):
elif type(terminator) == type(0): elif type(terminator) == type(0):
# numeric terminator # numeric terminator
n = terminator n = terminator
lb = lb
if lb < n: if lb < n:
self.collect_incoming_data (self.ac_in_buffer) self.collect_incoming_data (self.ac_in_buffer)
self.ac_in_buffer = '' self.ac_in_buffer = ''
...@@ -159,7 +158,13 @@ class async_chat (asyncore.dispatcher): ...@@ -159,7 +158,13 @@ class async_chat (asyncore.dispatcher):
def writable (self): def writable (self):
"predicate for inclusion in the writable for select()" "predicate for inclusion in the writable for select()"
return len(self.ac_out_buffer) or len(self.producer_fifo) or (not self.connected) # return len(self.ac_out_buffer) or len(self.producer_fifo) or (not self.connected)
# this is about twice as fast, though not as clear.
return not (
(self.ac_out_buffer is '') and
self.producer_fifo.is_empty() and
self.connected
)
def close_when_done (self): def close_when_done (self):
"automatically close this channel once the outgoing queue is empty" "automatically close this channel once the outgoing queue is empty"
...@@ -242,6 +247,9 @@ class fifo: ...@@ -242,6 +247,9 @@ class fifo:
def __len__ (self): def __len__ (self):
return len(self.list) return len(self.list)
def is_empty (self):
return self.list == []
def first (self): def first (self):
return self.list[0] return self.list[0]
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: asyncore.py,v 1.2 1999/04/09 00:37:33 amos Exp $ # $Id: asyncore.py,v 1.3 1999/05/26 02:08:30 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# ====================================================================== # ======================================================================
...@@ -37,17 +37,20 @@ if os.name == 'nt': ...@@ -37,17 +37,20 @@ if os.name == 'nt':
EALREADY = 10037 EALREADY = 10037
ECONNRESET = 10054 ECONNRESET = 10054
ENOTCONN = 10057 ENOTCONN = 10057
ESHUTDOWN = 10058
else: else:
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN
socket_map = {} socket_map = {}
def poll (timeout=0.0): def poll (timeout=0.0):
if socket_map: if socket_map:
sockets = socket_map.keys() r = []; w = []; e = []
r = filter (lambda x: x.readable(), sockets) for s in socket_map.keys():
w = filter (lambda x: x.writable(), sockets) if s.readable():
e = [] r.append (s)
if s.writable():
w.append (s)
(r,w,e) = select.select (r,w,e, timeout) (r,w,e) = select.select (r,w,e, timeout)
...@@ -140,11 +143,13 @@ class dispatcher: ...@@ -140,11 +143,13 @@ class dispatcher:
return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar) return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar)
def add_channel (self): def add_channel (self):
if __debug__:
self.log ('adding channel %s' % self) self.log ('adding channel %s' % self)
socket_map [self] = 1 socket_map [self] = 1
def del_channel (self): def del_channel (self):
if socket_map.has_key (self): if socket_map.has_key (self):
if __debug__:
self.log ('closing channel %d:%s' % (self.fileno(), self)) self.log ('closing channel %d:%s' % (self.fileno(), self))
del socket_map [self] del socket_map [self]
...@@ -155,7 +160,8 @@ class dispatcher: ...@@ -155,7 +160,8 @@ class dispatcher:
self.add_channel() self.add_channel()
def set_socket (self, socket): def set_socket (self, socket):
self.socket = socket # This is done so we can be called safely from __init__
self.__dict__['socket'] = socket
self.add_channel() self.add_channel()
def set_reuse_addr (self): def set_reuse_addr (self):
...@@ -245,7 +251,7 @@ class dispatcher: ...@@ -245,7 +251,7 @@ class dispatcher:
return data return data
except socket.error, why: except socket.error, why:
# winsock sometimes throws ENOTCONN # winsock sometimes throws ENOTCONN
if why[0] in [ECONNRESET, ENOTCONN]: if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
self.handle_close() self.handle_close()
return '' return ''
else: else:
...@@ -257,11 +263,9 @@ class dispatcher: ...@@ -257,11 +263,9 @@ class dispatcher:
# cheap inheritance, used to pass all other attribute # cheap inheritance, used to pass all other attribute
# references to the underlying socket object. # references to the underlying socket object.
# NOTE: this may be removed soon for performance reasons.
def __getattr__ (self, attr): def __getattr__ (self, attr):
if attr != 'socket':
return getattr (self.socket, attr) return getattr (self.socket, attr)
else:
raise AttributeError, attr
def log (self, message): def log (self, message):
print 'log:', message print 'log:', message
...@@ -310,21 +314,27 @@ class dispatcher: ...@@ -310,21 +314,27 @@ class dispatcher:
self.close() self.close()
def handle_expt (self): def handle_expt (self):
if __debug__:
self.log ('unhandled exception') self.log ('unhandled exception')
def handle_read (self): def handle_read (self):
if __debug__:
self.log ('unhandled read event') self.log ('unhandled read event')
def handle_write (self): def handle_write (self):
if __debug__:
self.log ('unhandled write event') self.log ('unhandled write event')
def handle_connect (self): def handle_connect (self):
if __debug__:
self.log ('unhandled connect event') self.log ('unhandled connect event')
def handle_accept (self): def handle_accept (self):
if __debug__:
self.log ('unhandled accept event') self.log ('unhandled accept event')
def handle_close (self): def handle_close (self):
if __debug__:
self.log ('unhandled close event') self.log ('unhandled close event')
self.close() self.close()
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# If you are interested in using this software in a commercial context, # If you are interested in using this software in a commercial context,
# or in purchasing support, please contact the author. # or in purchasing support, please contact the author.
RCS_ID = '$Id: ftp_server.py,v 1.4 1999/04/29 23:36:09 amos Exp $' RCS_ID = '$Id: ftp_server.py,v 1.5 1999/05/26 02:08:30 amos Exp $'
# An extensible, configurable, asynchronous FTP server. # An extensible, configurable, asynchronous FTP server.
# #
...@@ -54,9 +54,6 @@ import time ...@@ -54,9 +54,6 @@ import time
VERSION = string.split(RCS_ID)[2] VERSION = string.split(RCS_ID)[2]
IP_ADDRESS = socket.gethostbyname (socket.gethostname())
HOSTNAME = socket.gethostbyaddr (IP_ADDRESS)[0]
from counter import counter from counter import counter
import producers import producers
import status_handler import status_handler
...@@ -286,7 +283,7 @@ class ftp_channel (asynchat.async_chat): ...@@ -286,7 +283,7 @@ class ftp_channel (asynchat.async_chat):
if pa: if pa:
if pa.ready: if pa.ready:
# a connection has already been made. # a connection has already been made.
conn, addr = self.passive_acceptor.ready conn, addr = pa.ready
cdc = recv_channel (self, addr, fd) cdc = recv_channel (self, addr, fd)
cdc.set_socket (conn) cdc.set_socket (conn)
cdc.connected = 1 cdc.connected = 1
...@@ -698,14 +695,19 @@ class ftp_server (asyncore.dispatcher): ...@@ -698,14 +695,19 @@ class ftp_server (asyncore.dispatcher):
def __init__ ( def __init__ (
self, self,
authorizer, authorizer,
hostname =HOSTNAME, hostname =None,
port =21, port =21,
resolver =None, resolver =None,
logger_object=logger.file_logger (sys.stdout) logger_object=logger.file_logger (sys.stdout)
): ):
self.port = port self.port = port
self.authorizer = authorizer self.authorizer = authorizer
if hostname is None:
self.hostname = socket.gethostname()
else:
self.hostname = hostname self.hostname = hostname
# statistics # statistics
self.total_sessions = counter() self.total_sessions = counter()
self.closed_sessions = counter() self.closed_sessions = counter()
...@@ -1053,8 +1055,7 @@ if os.name == 'posix': ...@@ -1053,8 +1055,7 @@ if os.name == 'posix':
import sys import sys
fs = ftp_server ( fs = ftp_server (
unix_authorizer(), unix_authorizer(),
HOSTNAME, port=string.atoi (port)
string.atoi (port)
) )
try: try:
asyncore.loop() asyncore.loop()
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# interested in using this software in a commercial context, or in # interested in using this software in a commercial context, or in
# purchasing support, please contact the author. # purchasing support, please contact the author.
RCS_ID = '$Id: http_server.py,v 1.6 1999/04/09 00:37:33 amos Exp $' RCS_ID = '$Id: http_server.py,v 1.7 1999/05/26 02:08:30 amos Exp $'
# python modules # python modules
import os import os
...@@ -215,6 +215,12 @@ class http_request: ...@@ -215,6 +215,12 @@ class http_request:
wrap_in_chunking = 1 wrap_in_chunking = 1
else: else:
close_it = 1 close_it = 1
elif self.version is None:
# Although we don't *really* support http/0.9 (because we'd have to
# use \r\n as a terminator, and it would just yuck up a lot of stuff)
# it's very common for developers to not want to type a version number
# when using telnet to debug a server.
close_it = 1
outgoing_header = producers.simple_producer (self.build_reply_header()) outgoing_header = producers.simple_producer (self.build_reply_header())
...@@ -388,9 +394,25 @@ class http_channel (asynchat.async_chat): ...@@ -388,9 +394,25 @@ class http_channel (asynchat.async_chat):
return result return result
def recv (self, buffer_size): def recv (self, buffer_size):
try:
result = asynchat.async_chat.recv (self, buffer_size) result = asynchat.async_chat.recv (self, buffer_size)
self.server.bytes_in.increment (len(result)) self.server.bytes_in.increment (len(result))
return result return result
except MemoryError:
# --- Save a Trip to Your Service Provider ---
# It's possible for a process to eat up all the memory of
# the machine, and put it in an extremely wedged state,
# where medusa keeps running and can't be shut down. This
# is where MemoryError tends to get thrown, though of
# course it could get thrown elsewhere.
sys.exit ("Out of Memory!")
def handle_error (self):
t, v = sys.exc_info()[:2]
if t is SystemExit:
raise t, v
else:
asynchat.async_chat.handle_error (self)
def log (self, *args): def log (self, *args):
pass pass
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# #
RCS_ID = '$Id: resolver.py,v 1.2 1999/04/09 00:37:33 amos Exp $' RCS_ID = '$Id: resolver.py,v 1.3 1999/05/26 02:08:30 amos Exp $'
# Fast, low-overhead asynchronous name resolver. uses 'pre-cooked' # Fast, low-overhead asynchronous name resolver. uses 'pre-cooked'
# DNS requests, unpacks only as much as it needs of the reply. # DNS requests, unpacks only as much as it needs of the reply.
...@@ -12,6 +13,11 @@ RCS_ID = '$Id: resolver.py,v 1.2 1999/04/09 00:37:33 amos Exp $' ...@@ -12,6 +13,11 @@ RCS_ID = '$Id: resolver.py,v 1.2 1999/04/09 00:37:33 amos Exp $'
# see rfc1035 for details # see rfc1035 for details
import string import string
import asyncore
import socket
import sys
import time
from counter import counter
VERSION = string.split(RCS_ID)[2] VERSION = string.split(RCS_ID)[2]
...@@ -177,11 +183,6 @@ def unpack_ptr_reply (r): ...@@ -177,11 +183,6 @@ def unpack_ptr_reply (r):
return 0, None return 0, None
from counter import counter
import asyncore
import socket
import sys
# This is a UDP (datagram) resolver. # This is a UDP (datagram) resolver.
# #
...@@ -202,6 +203,7 @@ class resolver (asyncore.dispatcher): ...@@ -202,6 +203,7 @@ class resolver (asyncore.dispatcher):
self.create_socket (socket.AF_INET, socket.SOCK_DGRAM) self.create_socket (socket.AF_INET, socket.SOCK_DGRAM)
self.server = server self.server = server
self.request_map = {} self.request_map = {}
self.last_reap_time = int(time.time()) # reap every few minutes
def writable (self): def writable (self):
return 0 return 0
...@@ -213,18 +215,38 @@ class resolver (asyncore.dispatcher): ...@@ -213,18 +215,38 @@ class resolver (asyncore.dispatcher):
print 'closing!' print 'closing!'
self.close() self.close()
def handle_error (self): # don't close the connection on error
(file,fun,line), t, v, tbinfo = asyncore.compact_traceback()
print 'Problem with DNS lookup (%s:%s %s)' % (t, v, tbinfo)
def get_id (self): def get_id (self):
return (self.id.as_long() % (1<<16)) return (self.id.as_long() % (1<<16))
def reap (self): # find DNS requests that have timed out
now = int(time.time())
if now - self.last_reap_time > 180: # reap every 3 minutes
self.last_reap_time = now # update before we forget
for k,(host,unpack,callback,when) in self.request_map.items():
if now - when > 180: # over 3 minutes old
del self.request_map[k]
try: # same code as in handle_read
callback (host, 0, None) # timeout val is (0,None)
except:
(file,fun,line), t, v, tbinfo = asyncore.compact_traceback()
print t,v,tbinfo
def resolve (self, host, callback): def resolve (self, host, callback):
self.reap() # first, get rid of old guys
self.socket.sendto ( self.socket.sendto (
fast_address_request (host, self.get_id()), fast_address_request (host, self.get_id()),
(self.server, 53) (self.server, 53)
) )
self.request_map [self.get_id()] = host, unpack_address_reply, callback self.request_map [self.get_id()] = (
host, unpack_address_reply, callback, int(time.time()))
self.id.increment() self.id.increment()
def resolve_ptr (self, host, callback): def resolve_ptr (self, host, callback):
self.reap() # first, get rid of old guys
ip = string.split (host, '.') ip = string.split (host, '.')
ip.reverse() ip.reverse()
ip = string.join (ip, '.') + '.in-addr.arpa' ip = string.join (ip, '.') + '.in-addr.arpa'
...@@ -232,7 +254,8 @@ class resolver (asyncore.dispatcher): ...@@ -232,7 +254,8 @@ class resolver (asyncore.dispatcher):
fast_ptr_request (ip, self.get_id()), fast_ptr_request (ip, self.get_id()),
(self.server, 53) (self.server, 53)
) )
self.request_map [self.get_id()] = host, unpack_ptr_reply, callback self.request_map [self.get_id()] = (
host, unpack_ptr_reply, callback, int(time.time()))
self.id.increment() self.id.increment()
def handle_read (self): def handle_read (self):
...@@ -241,7 +264,7 @@ class resolver (asyncore.dispatcher): ...@@ -241,7 +264,7 @@ class resolver (asyncore.dispatcher):
# that <whence> is the server we sent the request to. # that <whence> is the server we sent the request to.
id = (ord(reply[0])<<8) + ord(reply[1]) id = (ord(reply[0])<<8) + ord(reply[1])
if self.request_map.has_key (id): if self.request_map.has_key (id):
host, unpack, callback = self.request_map[id] host, unpack, callback, when = self.request_map[id]
del self.request_map[id] del self.request_map[id]
ttl, answer = unpack (reply) ttl, answer = unpack (reply)
try: try:
...@@ -270,7 +293,6 @@ class rbl (resolver): ...@@ -270,7 +293,6 @@ class rbl (resolver):
print repr(r) print repr(r)
return 0, rcode # (ttl, answer) return 0, rcode # (ttl, answer)
import time
class hooked_callback: class hooked_callback:
def __init__ (self, hook, callback): def __init__ (self, hook, callback):
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: asynchat.py,v 1.7 1999/04/09 00:37:33 amos Exp $ # $Id: asynchat.py,v 1.8 1999/05/26 02:08:29 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# ====================================================================== # ======================================================================
...@@ -99,7 +99,6 @@ class async_chat (asyncore.dispatcher): ...@@ -99,7 +99,6 @@ class async_chat (asyncore.dispatcher):
elif type(terminator) == type(0): elif type(terminator) == type(0):
# numeric terminator # numeric terminator
n = terminator n = terminator
lb = lb
if lb < n: if lb < n:
self.collect_incoming_data (self.ac_in_buffer) self.collect_incoming_data (self.ac_in_buffer)
self.ac_in_buffer = '' self.ac_in_buffer = ''
...@@ -159,7 +158,13 @@ class async_chat (asyncore.dispatcher): ...@@ -159,7 +158,13 @@ class async_chat (asyncore.dispatcher):
def writable (self): def writable (self):
"predicate for inclusion in the writable for select()" "predicate for inclusion in the writable for select()"
return len(self.ac_out_buffer) or len(self.producer_fifo) or (not self.connected) # return len(self.ac_out_buffer) or len(self.producer_fifo) or (not self.connected)
# this is about twice as fast, though not as clear.
return not (
(self.ac_out_buffer is '') and
self.producer_fifo.is_empty() and
self.connected
)
def close_when_done (self): def close_when_done (self):
"automatically close this channel once the outgoing queue is empty" "automatically close this channel once the outgoing queue is empty"
...@@ -242,6 +247,9 @@ class fifo: ...@@ -242,6 +247,9 @@ class fifo:
def __len__ (self): def __len__ (self):
return len(self.list) return len(self.list)
def is_empty (self):
return self.list == []
def first (self): def first (self):
return self.list[0] return self.list[0]
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: asyncore.py,v 1.2 1999/04/09 00:37:33 amos Exp $ # $Id: asyncore.py,v 1.3 1999/05/26 02:08:30 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# ====================================================================== # ======================================================================
...@@ -37,17 +37,20 @@ if os.name == 'nt': ...@@ -37,17 +37,20 @@ if os.name == 'nt':
EALREADY = 10037 EALREADY = 10037
ECONNRESET = 10054 ECONNRESET = 10054
ENOTCONN = 10057 ENOTCONN = 10057
ESHUTDOWN = 10058
else: else:
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN
socket_map = {} socket_map = {}
def poll (timeout=0.0): def poll (timeout=0.0):
if socket_map: if socket_map:
sockets = socket_map.keys() r = []; w = []; e = []
r = filter (lambda x: x.readable(), sockets) for s in socket_map.keys():
w = filter (lambda x: x.writable(), sockets) if s.readable():
e = [] r.append (s)
if s.writable():
w.append (s)
(r,w,e) = select.select (r,w,e, timeout) (r,w,e) = select.select (r,w,e, timeout)
...@@ -140,11 +143,13 @@ class dispatcher: ...@@ -140,11 +143,13 @@ class dispatcher:
return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar) return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar)
def add_channel (self): def add_channel (self):
if __debug__:
self.log ('adding channel %s' % self) self.log ('adding channel %s' % self)
socket_map [self] = 1 socket_map [self] = 1
def del_channel (self): def del_channel (self):
if socket_map.has_key (self): if socket_map.has_key (self):
if __debug__:
self.log ('closing channel %d:%s' % (self.fileno(), self)) self.log ('closing channel %d:%s' % (self.fileno(), self))
del socket_map [self] del socket_map [self]
...@@ -155,7 +160,8 @@ class dispatcher: ...@@ -155,7 +160,8 @@ class dispatcher:
self.add_channel() self.add_channel()
def set_socket (self, socket): def set_socket (self, socket):
self.socket = socket # This is done so we can be called safely from __init__
self.__dict__['socket'] = socket
self.add_channel() self.add_channel()
def set_reuse_addr (self): def set_reuse_addr (self):
...@@ -245,7 +251,7 @@ class dispatcher: ...@@ -245,7 +251,7 @@ class dispatcher:
return data return data
except socket.error, why: except socket.error, why:
# winsock sometimes throws ENOTCONN # winsock sometimes throws ENOTCONN
if why[0] in [ECONNRESET, ENOTCONN]: if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
self.handle_close() self.handle_close()
return '' return ''
else: else:
...@@ -257,11 +263,9 @@ class dispatcher: ...@@ -257,11 +263,9 @@ class dispatcher:
# cheap inheritance, used to pass all other attribute # cheap inheritance, used to pass all other attribute
# references to the underlying socket object. # references to the underlying socket object.
# NOTE: this may be removed soon for performance reasons.
def __getattr__ (self, attr): def __getattr__ (self, attr):
if attr != 'socket':
return getattr (self.socket, attr) return getattr (self.socket, attr)
else:
raise AttributeError, attr
def log (self, message): def log (self, message):
print 'log:', message print 'log:', message
...@@ -310,21 +314,27 @@ class dispatcher: ...@@ -310,21 +314,27 @@ class dispatcher:
self.close() self.close()
def handle_expt (self): def handle_expt (self):
if __debug__:
self.log ('unhandled exception') self.log ('unhandled exception')
def handle_read (self): def handle_read (self):
if __debug__:
self.log ('unhandled read event') self.log ('unhandled read event')
def handle_write (self): def handle_write (self):
if __debug__:
self.log ('unhandled write event') self.log ('unhandled write event')
def handle_connect (self): def handle_connect (self):
if __debug__:
self.log ('unhandled connect event') self.log ('unhandled connect event')
def handle_accept (self): def handle_accept (self):
if __debug__:
self.log ('unhandled accept event') self.log ('unhandled accept event')
def handle_close (self): def handle_close (self):
if __debug__:
self.log ('unhandled close event') self.log ('unhandled close event')
self.close() self.close()
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# If you are interested in using this software in a commercial context, # If you are interested in using this software in a commercial context,
# or in purchasing support, please contact the author. # or in purchasing support, please contact the author.
RCS_ID = '$Id: ftp_server.py,v 1.4 1999/04/29 23:36:09 amos Exp $' RCS_ID = '$Id: ftp_server.py,v 1.5 1999/05/26 02:08:30 amos Exp $'
# An extensible, configurable, asynchronous FTP server. # An extensible, configurable, asynchronous FTP server.
# #
...@@ -54,9 +54,6 @@ import time ...@@ -54,9 +54,6 @@ import time
VERSION = string.split(RCS_ID)[2] VERSION = string.split(RCS_ID)[2]
IP_ADDRESS = socket.gethostbyname (socket.gethostname())
HOSTNAME = socket.gethostbyaddr (IP_ADDRESS)[0]
from counter import counter from counter import counter
import producers import producers
import status_handler import status_handler
...@@ -286,7 +283,7 @@ class ftp_channel (asynchat.async_chat): ...@@ -286,7 +283,7 @@ class ftp_channel (asynchat.async_chat):
if pa: if pa:
if pa.ready: if pa.ready:
# a connection has already been made. # a connection has already been made.
conn, addr = self.passive_acceptor.ready conn, addr = pa.ready
cdc = recv_channel (self, addr, fd) cdc = recv_channel (self, addr, fd)
cdc.set_socket (conn) cdc.set_socket (conn)
cdc.connected = 1 cdc.connected = 1
...@@ -698,14 +695,19 @@ class ftp_server (asyncore.dispatcher): ...@@ -698,14 +695,19 @@ class ftp_server (asyncore.dispatcher):
def __init__ ( def __init__ (
self, self,
authorizer, authorizer,
hostname =HOSTNAME, hostname =None,
port =21, port =21,
resolver =None, resolver =None,
logger_object=logger.file_logger (sys.stdout) logger_object=logger.file_logger (sys.stdout)
): ):
self.port = port self.port = port
self.authorizer = authorizer self.authorizer = authorizer
if hostname is None:
self.hostname = socket.gethostname()
else:
self.hostname = hostname self.hostname = hostname
# statistics # statistics
self.total_sessions = counter() self.total_sessions = counter()
self.closed_sessions = counter() self.closed_sessions = counter()
...@@ -1053,8 +1055,7 @@ if os.name == 'posix': ...@@ -1053,8 +1055,7 @@ if os.name == 'posix':
import sys import sys
fs = ftp_server ( fs = ftp_server (
unix_authorizer(), unix_authorizer(),
HOSTNAME, port=string.atoi (port)
string.atoi (port)
) )
try: try:
asyncore.loop() asyncore.loop()
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# interested in using this software in a commercial context, or in # interested in using this software in a commercial context, or in
# purchasing support, please contact the author. # purchasing support, please contact the author.
RCS_ID = '$Id: http_server.py,v 1.6 1999/04/09 00:37:33 amos Exp $' RCS_ID = '$Id: http_server.py,v 1.7 1999/05/26 02:08:30 amos Exp $'
# python modules # python modules
import os import os
...@@ -215,6 +215,12 @@ class http_request: ...@@ -215,6 +215,12 @@ class http_request:
wrap_in_chunking = 1 wrap_in_chunking = 1
else: else:
close_it = 1 close_it = 1
elif self.version is None:
# Although we don't *really* support http/0.9 (because we'd have to
# use \r\n as a terminator, and it would just yuck up a lot of stuff)
# it's very common for developers to not want to type a version number
# when using telnet to debug a server.
close_it = 1
outgoing_header = producers.simple_producer (self.build_reply_header()) outgoing_header = producers.simple_producer (self.build_reply_header())
...@@ -388,9 +394,25 @@ class http_channel (asynchat.async_chat): ...@@ -388,9 +394,25 @@ class http_channel (asynchat.async_chat):
return result return result
def recv (self, buffer_size): def recv (self, buffer_size):
try:
result = asynchat.async_chat.recv (self, buffer_size) result = asynchat.async_chat.recv (self, buffer_size)
self.server.bytes_in.increment (len(result)) self.server.bytes_in.increment (len(result))
return result return result
except MemoryError:
# --- Save a Trip to Your Service Provider ---
# It's possible for a process to eat up all the memory of
# the machine, and put it in an extremely wedged state,
# where medusa keeps running and can't be shut down. This
# is where MemoryError tends to get thrown, though of
# course it could get thrown elsewhere.
sys.exit ("Out of Memory!")
def handle_error (self):
t, v = sys.exc_info()[:2]
if t is SystemExit:
raise t, v
else:
asynchat.async_chat.handle_error (self)
def log (self, *args): def log (self, *args):
pass pass
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# #
RCS_ID = '$Id: resolver.py,v 1.2 1999/04/09 00:37:33 amos Exp $' RCS_ID = '$Id: resolver.py,v 1.3 1999/05/26 02:08:30 amos Exp $'
# Fast, low-overhead asynchronous name resolver. uses 'pre-cooked' # Fast, low-overhead asynchronous name resolver. uses 'pre-cooked'
# DNS requests, unpacks only as much as it needs of the reply. # DNS requests, unpacks only as much as it needs of the reply.
...@@ -12,6 +13,11 @@ RCS_ID = '$Id: resolver.py,v 1.2 1999/04/09 00:37:33 amos Exp $' ...@@ -12,6 +13,11 @@ RCS_ID = '$Id: resolver.py,v 1.2 1999/04/09 00:37:33 amos Exp $'
# see rfc1035 for details # see rfc1035 for details
import string import string
import asyncore
import socket
import sys
import time
from counter import counter
VERSION = string.split(RCS_ID)[2] VERSION = string.split(RCS_ID)[2]
...@@ -177,11 +183,6 @@ def unpack_ptr_reply (r): ...@@ -177,11 +183,6 @@ def unpack_ptr_reply (r):
return 0, None return 0, None
from counter import counter
import asyncore
import socket
import sys
# This is a UDP (datagram) resolver. # This is a UDP (datagram) resolver.
# #
...@@ -202,6 +203,7 @@ class resolver (asyncore.dispatcher): ...@@ -202,6 +203,7 @@ class resolver (asyncore.dispatcher):
self.create_socket (socket.AF_INET, socket.SOCK_DGRAM) self.create_socket (socket.AF_INET, socket.SOCK_DGRAM)
self.server = server self.server = server
self.request_map = {} self.request_map = {}
self.last_reap_time = int(time.time()) # reap every few minutes
def writable (self): def writable (self):
return 0 return 0
...@@ -213,18 +215,38 @@ class resolver (asyncore.dispatcher): ...@@ -213,18 +215,38 @@ class resolver (asyncore.dispatcher):
print 'closing!' print 'closing!'
self.close() self.close()
def handle_error (self): # don't close the connection on error
(file,fun,line), t, v, tbinfo = asyncore.compact_traceback()
print 'Problem with DNS lookup (%s:%s %s)' % (t, v, tbinfo)
def get_id (self): def get_id (self):
return (self.id.as_long() % (1<<16)) return (self.id.as_long() % (1<<16))
def reap (self): # find DNS requests that have timed out
now = int(time.time())
if now - self.last_reap_time > 180: # reap every 3 minutes
self.last_reap_time = now # update before we forget
for k,(host,unpack,callback,when) in self.request_map.items():
if now - when > 180: # over 3 minutes old
del self.request_map[k]
try: # same code as in handle_read
callback (host, 0, None) # timeout val is (0,None)
except:
(file,fun,line), t, v, tbinfo = asyncore.compact_traceback()
print t,v,tbinfo
def resolve (self, host, callback): def resolve (self, host, callback):
self.reap() # first, get rid of old guys
self.socket.sendto ( self.socket.sendto (
fast_address_request (host, self.get_id()), fast_address_request (host, self.get_id()),
(self.server, 53) (self.server, 53)
) )
self.request_map [self.get_id()] = host, unpack_address_reply, callback self.request_map [self.get_id()] = (
host, unpack_address_reply, callback, int(time.time()))
self.id.increment() self.id.increment()
def resolve_ptr (self, host, callback): def resolve_ptr (self, host, callback):
self.reap() # first, get rid of old guys
ip = string.split (host, '.') ip = string.split (host, '.')
ip.reverse() ip.reverse()
ip = string.join (ip, '.') + '.in-addr.arpa' ip = string.join (ip, '.') + '.in-addr.arpa'
...@@ -232,7 +254,8 @@ class resolver (asyncore.dispatcher): ...@@ -232,7 +254,8 @@ class resolver (asyncore.dispatcher):
fast_ptr_request (ip, self.get_id()), fast_ptr_request (ip, self.get_id()),
(self.server, 53) (self.server, 53)
) )
self.request_map [self.get_id()] = host, unpack_ptr_reply, callback self.request_map [self.get_id()] = (
host, unpack_ptr_reply, callback, int(time.time()))
self.id.increment() self.id.increment()
def handle_read (self): def handle_read (self):
...@@ -241,7 +264,7 @@ class resolver (asyncore.dispatcher): ...@@ -241,7 +264,7 @@ class resolver (asyncore.dispatcher):
# that <whence> is the server we sent the request to. # that <whence> is the server we sent the request to.
id = (ord(reply[0])<<8) + ord(reply[1]) id = (ord(reply[0])<<8) + ord(reply[1])
if self.request_map.has_key (id): if self.request_map.has_key (id):
host, unpack, callback = self.request_map[id] host, unpack, callback, when = self.request_map[id]
del self.request_map[id] del self.request_map[id]
ttl, answer = unpack (reply) ttl, answer = unpack (reply)
try: try:
...@@ -270,7 +293,6 @@ class rbl (resolver): ...@@ -270,7 +293,6 @@ class rbl (resolver):
print repr(r) print repr(r)
return 0, rcode # (ttl, answer) return 0, rcode # (ttl, answer)
import time
class hooked_callback: class hooked_callback:
def __init__ (self, hook, callback): def __init__ (self, hook, callback):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment