Commit 5e529dcf authored by Amos Latteier's avatar Amos Latteier

Synched with latest medusa sources from CVS. The main changes are the...

Synched with latest medusa sources from CVS. The main changes are the structure of asyncore.socket_map which now maps fds to channels which should provide a slight performance improvement.
parent 09bb46b6
# -*- Mode: Python; tab-width: 4 -*-
# $Id: asynchat.py,v 1.9 1999/07/19 17:43:47 amos Exp $
# $Id: asynchat.py,v 1.10 2000/01/14 02:35:56 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com>
# ======================================================================
......@@ -219,7 +219,7 @@ class async_chat (asyncore.dispatcher):
def discard_buffers (self):
# Emergencies only!
self.ac_in_buffer = ''
self.ac_out_buffer == ''
self.ac_out_buffer = ''
while self.producer_fifo:
self.producer_fifo.pop()
......
# -*- Mode: Python; tab-width: 4 -*-
# $Id: asyncore.py,v 1.6 1999/07/26 07:06:36 amos Exp $
# $Id: asyncore.py,v 1.7 2000/01/14 02:35:56 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com>
# ======================================================================
......@@ -25,6 +25,7 @@
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# ======================================================================
import exceptions
import select
import socket
import string
......@@ -41,60 +42,83 @@ if os.name == 'nt':
else:
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN
socket_map = {}
try:
socket_map
except NameError:
socket_map = {}
class ExitNow (exceptions.Exception):
pass
DEBUG = 0
def poll (timeout=0.0):
global DEBUG
if socket_map:
r = []; w = []; e = []
for s in socket_map.keys():
if s.readable():
r.append (s)
if s.writable():
w.append (s)
for fd, obj in socket_map.items():
if obj.readable():
r.append (fd)
if obj.writable():
w.append (fd)
r,w,e = select.select (r,w,e, timeout)
(r,w,e) = select.select (r,w,e, timeout)
if DEBUG:
print r,w,e
for x in r:
for fd in r:
try:
x.handle_read_event()
except:
x.handle_error()
for x in w:
obj = socket_map[fd]
try:
obj.handle_read_event()
except ExitNow:
raise ExitNow
except:
obj.handle_error()
except KeyError:
pass
for fd in w:
try:
x.handle_write_event()
except:
x.handle_error()
obj = socket_map[fd]
try:
obj.handle_write_event()
except ExitNow:
raise ExitNow
except:
obj.handle_error()
except KeyError:
pass
def poll2 (timeout=0.0):
import poll
# timeout is in milliseconds
timeout = int(timeout*1000)
if socket_map:
fd_map = {}
for s in socket_map.keys():
fd_map[s.fileno()] = s
l = []
for fd, s in fd_map.items():
for fd, obj in socket_map.items():
flags = 0
if s.readable():
if obj.readable():
flags = poll.POLLIN
if s.writable():
if obj.writable():
flags = flags | poll.POLLOUT
if flags:
l.append (fd, flags)
r = poll.poll (l, timeout)
for fd, flags in r:
s = fd_map[fd]
try:
if (flags & poll.POLLIN):
s.handle_read_event()
if (flags & poll.POLLOUT):
s.handle_write_event()
if (flags & poll.POLLERR):
s.handle_expt_event()
except:
s.handle_error()
obj = socket_map[fd]
try:
if (flags & poll.POLLIN):
obj.handle_read_event()
if (flags & poll.POLLOUT):
obj.handle_write_event()
except ExitNow:
raise ExitNow
except:
obj.handle_error()
except KeyError:
pass
def loop (timeout=30.0, use_poll=0):
......@@ -143,23 +167,25 @@ class dispatcher:
return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar)
def add_channel (self):
self.log_info ('adding channel %s' % self)
socket_map [self] = 1
#self.log_info ('adding channel %s' % self)
socket_map [self._fileno] = self
def del_channel (self):
if socket_map.has_key (self):
self.log_info ('closing channel %d:%s' % (self.fileno(), self))
del socket_map [self]
fd = self._fileno
if socket_map.has_key (fd):
#self.log_info ('closing channel %d:%s' % (fd, self))
del socket_map [fd]
def create_socket (self, family, type):
self.family_and_type = family, type
self.socket = socket.socket (family, type)
self.socket.setblocking(0)
self._fileno = self.socket.fileno()
self.add_channel()
def set_socket (self, socket):
# This is done so we can be called safely from __init__
self.__dict__['socket'] = socket
def set_socket (self, sock):
self.__dict__['socket'] = sock
self._fileno = sock.fileno()
self.add_channel()
def set_reuse_addr (self):
......@@ -261,20 +287,19 @@ class dispatcher:
# cheap inheritance, used to pass all other attribute
# references to the underlying socket object.
# NOTE: this may be removed soon for performance reasons.
def __getattr__ (self, attr):
return getattr (self.socket, attr)
# log and log_info maybe overriden to provide more sophisitcated
# logging and warning methods. In general, log is for 'hit' logging
# and 'log_info' is for informational, warning and error logging.
def log (self, message):
print 'log:', message
sys.stderr.write ('log: %s\n' % str(message))
def log_info (self, message, type='info'):
if __debug__ or type != 'info':
print '%s: %s' %(type, message)
print '%s: %s' % (type, message)
def handle_read_event (self):
if self.accepting:
......@@ -398,7 +423,7 @@ def compact_traceback ():
def close_all ():
global socket_map
for x in socket_map.keys():
for x in socket_map.values():
x.socket.close()
socket_map.clear()
......@@ -449,6 +474,7 @@ if os.name == 'posix':
self.set_file (fd)
def set_file (self, fd):
self._fileno = fd
self.socket = file_wrapper (fd)
self.add_channel()
......@@ -8,7 +8,7 @@
# If you are interested in using this software in a commercial context,
# or in purchasing support, please contact the author.
RCS_ID = '$Id: ftp_server.py,v 1.8 1999/11/15 21:53:56 amos Exp $'
RCS_ID = '$Id: ftp_server.py,v 1.9 2000/01/14 02:35:56 amos Exp $'
# An extensible, configurable, asynchronous FTP server.
#
......@@ -336,6 +336,7 @@ class ftp_channel (asynchat.async_chat):
self.current_mode = t
self.respond ('200 Type set to %s.' % self.type_map[t])
def cmd_quit (self, line):
'terminate session'
self.respond ('221 Goodbye.')
......@@ -847,13 +848,16 @@ class xmit_channel (asynchat.async_chat):
self.channel = channel
self.client_addr = client_addr
asynchat.async_chat.__init__ (self)
# def __del__ (self):
# print 'xmit_channel.__del__()'
def readable (self):
return 0
def log(self, *args):
def log (*args):
pass
def readable (self):
return not self.connected
def writable (self):
return 1
......@@ -1054,13 +1058,7 @@ if os.name == 'posix':
self.log_info('FTP server shutting down. (received SIGINT)', 'warning')
# close everything down on SIGINT.
# of course this should be a cleaner shutdown.
sm = socket.socket_map
socket.socket_map = {}
for sock in sm.values():
try:
sock.close()
except:
pass
asyncore.close_all()
if __name__ == '__main__':
test (sys.argv[1])
......
......@@ -9,7 +9,7 @@
# interested in using this software in a commercial context, or in
# purchasing support, please contact the author.
RCS_ID = '$Id: http_server.py,v 1.13 1999/11/15 21:53:56 amos Exp $'
RCS_ID = '$Id: http_server.py,v 1.14 2000/01/14 02:35:56 amos Exp $'
# python modules
import os
......@@ -269,7 +269,7 @@ class http_request:
user_agent=self.get_header('user-agent')
if not user_agent: user_agent=''
referer=self.get_header('referer')
if not referer: referer=''
if not referer: referer=''
self.channel.server.logger.log (
self.channel.addr[0],
' - - [%s] "%s" %d %d "%s" "%s"\n' % (
......@@ -385,7 +385,7 @@ class http_channel (asynchat.async_chat):
def kill_zombies (self):
now = int (time.time())
for channel in asyncore.socket_map.keys():
for channel in asyncore.socket_map.values():
if channel.__class__ == self.__class__:
if (now - channel.creation_time) > channel.zombie_timeout:
channel.close()
......@@ -448,7 +448,7 @@ class http_channel (asynchat.async_chat):
# --------------------------------------------------
# crack the request header
# --------------------------------------------------
while lines and not lines[0]:
# as per the suggestion of http-1.1 section 4.1, (and
# Eric Parker <eparker@zyvex.com>), ignore a leading
......@@ -461,27 +461,18 @@ class http_channel (asynchat.async_chat):
return
request = lines[0]
try:
command, uri, version = crack_request (request)
except:
# deal with broken HTTP requests
try:
# maybe there were spaces in the URL
parts=string.split(request)
command, uri, version = crack_request(
'%s %s %s' % (parts[0], parts[1], parts[-1]))
except:
self.log_info('Bad HTTP request: %s' % request, 'error')
r = http_request (self, request,
None, None, None, join_headers(lines[1:]))
r.error(400)
return
command, uri, version = crack_request (request)
header = join_headers (lines[1:])
r = http_request (self, request, command, uri, version, header)
self.request_counter.increment()
self.server.total_requests.increment()
if command is None:
self.log_info('Bad HTTP request: %s' % request, 'error')
r.error(400)
return
# --------------------------------------------------
# handler selection and dispatch
# --------------------------------------------------
......@@ -612,7 +603,14 @@ class http_server (asyncore.dispatcher):
# accept. socketmodule.c:makesockaddr complains that the
# address family is unknown. We don't want the whole server
# to shut down because of this.
self.log_info('Server accept() threw an exception', 'warning')
self.log_info ('warning: server accept() threw an exception', 'warning')
return
except TypeError:
# unpack non-sequence. this can happen when a read event
# fires on a listening socket, but when we call accept()
# we get EWOULDBLOCK, so dispatcher.accept() returns None.
# Seen on FreeBSD3.
self.log_info ('warning: server accept() threw EWOULDBLOCK', 'warning')
return
self.channel_class (self, conn, addr)
......@@ -689,6 +687,8 @@ def crack_request (r):
else:
version = None
return string.lower (REQUEST.group (1)), REQUEST.group(2), version
else:
return None, None, None
class fifo:
def __init__ (self, list=None):
......
This diff is collapsed.
......@@ -60,7 +60,7 @@ class monitor_client (asynchat.async_chat):
def handle_close (self):
# close all the channels, which will make the standard main
# loop exit.
map (lambda x: x.close(), asyncore.socket_map.keys())
map (lambda x: x.close(), asyncore.socket_map.values())
def log (self, *ignore):
pass
......
This diff is collapsed.
# -*- Mode: Python; tab-width: 4 -*-
# $Id: asynchat.py,v 1.9 1999/07/19 17:43:47 amos Exp $
# $Id: asynchat.py,v 1.10 2000/01/14 02:35:56 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com>
# ======================================================================
......@@ -219,7 +219,7 @@ class async_chat (asyncore.dispatcher):
def discard_buffers (self):
# Emergencies only!
self.ac_in_buffer = ''
self.ac_out_buffer == ''
self.ac_out_buffer = ''
while self.producer_fifo:
self.producer_fifo.pop()
......
# -*- Mode: Python; tab-width: 4 -*-
# $Id: asyncore.py,v 1.6 1999/07/26 07:06:36 amos Exp $
# $Id: asyncore.py,v 1.7 2000/01/14 02:35:56 amos Exp $
# Author: Sam Rushing <rushing@nightmare.com>
# ======================================================================
......@@ -25,6 +25,7 @@
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# ======================================================================
import exceptions
import select
import socket
import string
......@@ -41,60 +42,83 @@ if os.name == 'nt':
else:
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN
socket_map = {}
try:
socket_map
except NameError:
socket_map = {}
class ExitNow (exceptions.Exception):
pass
DEBUG = 0
def poll (timeout=0.0):
global DEBUG
if socket_map:
r = []; w = []; e = []
for s in socket_map.keys():
if s.readable():
r.append (s)
if s.writable():
w.append (s)
for fd, obj in socket_map.items():
if obj.readable():
r.append (fd)
if obj.writable():
w.append (fd)
r,w,e = select.select (r,w,e, timeout)
(r,w,e) = select.select (r,w,e, timeout)
if DEBUG:
print r,w,e
for x in r:
for fd in r:
try:
x.handle_read_event()
except:
x.handle_error()
for x in w:
obj = socket_map[fd]
try:
obj.handle_read_event()
except ExitNow:
raise ExitNow
except:
obj.handle_error()
except KeyError:
pass
for fd in w:
try:
x.handle_write_event()
except:
x.handle_error()
obj = socket_map[fd]
try:
obj.handle_write_event()
except ExitNow:
raise ExitNow
except:
obj.handle_error()
except KeyError:
pass
def poll2 (timeout=0.0):
import poll
# timeout is in milliseconds
timeout = int(timeout*1000)
if socket_map:
fd_map = {}
for s in socket_map.keys():
fd_map[s.fileno()] = s
l = []
for fd, s in fd_map.items():
for fd, obj in socket_map.items():
flags = 0
if s.readable():
if obj.readable():
flags = poll.POLLIN
if s.writable():
if obj.writable():
flags = flags | poll.POLLOUT
if flags:
l.append (fd, flags)
r = poll.poll (l, timeout)
for fd, flags in r:
s = fd_map[fd]
try:
if (flags & poll.POLLIN):
s.handle_read_event()
if (flags & poll.POLLOUT):
s.handle_write_event()
if (flags & poll.POLLERR):
s.handle_expt_event()
except:
s.handle_error()
obj = socket_map[fd]
try:
if (flags & poll.POLLIN):
obj.handle_read_event()
if (flags & poll.POLLOUT):
obj.handle_write_event()
except ExitNow:
raise ExitNow
except:
obj.handle_error()
except KeyError:
pass
def loop (timeout=30.0, use_poll=0):
......@@ -143,23 +167,25 @@ class dispatcher:
return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar)
def add_channel (self):
self.log_info ('adding channel %s' % self)
socket_map [self] = 1
#self.log_info ('adding channel %s' % self)
socket_map [self._fileno] = self
def del_channel (self):
if socket_map.has_key (self):
self.log_info ('closing channel %d:%s' % (self.fileno(), self))
del socket_map [self]
fd = self._fileno
if socket_map.has_key (fd):
#self.log_info ('closing channel %d:%s' % (fd, self))
del socket_map [fd]
def create_socket (self, family, type):
self.family_and_type = family, type
self.socket = socket.socket (family, type)
self.socket.setblocking(0)
self._fileno = self.socket.fileno()
self.add_channel()
def set_socket (self, socket):
# This is done so we can be called safely from __init__
self.__dict__['socket'] = socket
def set_socket (self, sock):
self.__dict__['socket'] = sock
self._fileno = sock.fileno()
self.add_channel()
def set_reuse_addr (self):
......@@ -261,20 +287,19 @@ class dispatcher:
# cheap inheritance, used to pass all other attribute
# references to the underlying socket object.
# NOTE: this may be removed soon for performance reasons.
def __getattr__ (self, attr):
return getattr (self.socket, attr)
# log and log_info maybe overriden to provide more sophisitcated
# logging and warning methods. In general, log is for 'hit' logging
# and 'log_info' is for informational, warning and error logging.
def log (self, message):
print 'log:', message
sys.stderr.write ('log: %s\n' % str(message))
def log_info (self, message, type='info'):
if __debug__ or type != 'info':
print '%s: %s' %(type, message)
print '%s: %s' % (type, message)
def handle_read_event (self):
if self.accepting:
......@@ -398,7 +423,7 @@ def compact_traceback ():
def close_all ():
global socket_map
for x in socket_map.keys():
for x in socket_map.values():
x.socket.close()
socket_map.clear()
......@@ -449,6 +474,7 @@ if os.name == 'posix':
self.set_file (fd)
def set_file (self, fd):
self._fileno = fd
self.socket = file_wrapper (fd)
self.add_channel()
......@@ -8,7 +8,7 @@
# If you are interested in using this software in a commercial context,
# or in purchasing support, please contact the author.
RCS_ID = '$Id: ftp_server.py,v 1.8 1999/11/15 21:53:56 amos Exp $'
RCS_ID = '$Id: ftp_server.py,v 1.9 2000/01/14 02:35:56 amos Exp $'
# An extensible, configurable, asynchronous FTP server.
#
......@@ -336,6 +336,7 @@ class ftp_channel (asynchat.async_chat):
self.current_mode = t
self.respond ('200 Type set to %s.' % self.type_map[t])
def cmd_quit (self, line):
'terminate session'
self.respond ('221 Goodbye.')
......@@ -847,13 +848,16 @@ class xmit_channel (asynchat.async_chat):
self.channel = channel
self.client_addr = client_addr
asynchat.async_chat.__init__ (self)
# def __del__ (self):
# print 'xmit_channel.__del__()'
def readable (self):
return 0
def log(self, *args):
def log (*args):
pass
def readable (self):
return not self.connected
def writable (self):
return 1
......@@ -1054,13 +1058,7 @@ if os.name == 'posix':
self.log_info('FTP server shutting down. (received SIGINT)', 'warning')
# close everything down on SIGINT.
# of course this should be a cleaner shutdown.
sm = socket.socket_map
socket.socket_map = {}
for sock in sm.values():
try:
sock.close()
except:
pass
asyncore.close_all()
if __name__ == '__main__':
test (sys.argv[1])
......
......@@ -9,7 +9,7 @@
# interested in using this software in a commercial context, or in
# purchasing support, please contact the author.
RCS_ID = '$Id: http_server.py,v 1.13 1999/11/15 21:53:56 amos Exp $'
RCS_ID = '$Id: http_server.py,v 1.14 2000/01/14 02:35:56 amos Exp $'
# python modules
import os
......@@ -269,7 +269,7 @@ class http_request:
user_agent=self.get_header('user-agent')
if not user_agent: user_agent=''
referer=self.get_header('referer')
if not referer: referer=''
if not referer: referer=''
self.channel.server.logger.log (
self.channel.addr[0],
' - - [%s] "%s" %d %d "%s" "%s"\n' % (
......@@ -385,7 +385,7 @@ class http_channel (asynchat.async_chat):
def kill_zombies (self):
now = int (time.time())
for channel in asyncore.socket_map.keys():
for channel in asyncore.socket_map.values():
if channel.__class__ == self.__class__:
if (now - channel.creation_time) > channel.zombie_timeout:
channel.close()
......@@ -448,7 +448,7 @@ class http_channel (asynchat.async_chat):
# --------------------------------------------------
# crack the request header
# --------------------------------------------------
while lines and not lines[0]:
# as per the suggestion of http-1.1 section 4.1, (and
# Eric Parker <eparker@zyvex.com>), ignore a leading
......@@ -461,27 +461,18 @@ class http_channel (asynchat.async_chat):
return
request = lines[0]
try:
command, uri, version = crack_request (request)
except:
# deal with broken HTTP requests
try:
# maybe there were spaces in the URL
parts=string.split(request)
command, uri, version = crack_request(
'%s %s %s' % (parts[0], parts[1], parts[-1]))
except:
self.log_info('Bad HTTP request: %s' % request, 'error')
r = http_request (self, request,
None, None, None, join_headers(lines[1:]))
r.error(400)
return
command, uri, version = crack_request (request)
header = join_headers (lines[1:])
r = http_request (self, request, command, uri, version, header)
self.request_counter.increment()
self.server.total_requests.increment()
if command is None:
self.log_info('Bad HTTP request: %s' % request, 'error')
r.error(400)
return
# --------------------------------------------------
# handler selection and dispatch
# --------------------------------------------------
......@@ -612,7 +603,14 @@ class http_server (asyncore.dispatcher):
# accept. socketmodule.c:makesockaddr complains that the
# address family is unknown. We don't want the whole server
# to shut down because of this.
self.log_info('Server accept() threw an exception', 'warning')
self.log_info ('warning: server accept() threw an exception', 'warning')
return
except TypeError:
# unpack non-sequence. this can happen when a read event
# fires on a listening socket, but when we call accept()
# we get EWOULDBLOCK, so dispatcher.accept() returns None.
# Seen on FreeBSD3.
self.log_info ('warning: server accept() threw EWOULDBLOCK', 'warning')
return
self.channel_class (self, conn, addr)
......@@ -689,6 +687,8 @@ def crack_request (r):
else:
version = None
return string.lower (REQUEST.group (1)), REQUEST.group(2), version
else:
return None, None, None
class fifo:
def __init__ (self, list=None):
......
This diff is collapsed.
......@@ -60,7 +60,7 @@ class monitor_client (asynchat.async_chat):
def handle_close (self):
# close all the channels, which will make the standard main
# loop exit.
map (lambda x: x.close(), asyncore.socket_map.keys())
map (lambda x: x.close(), asyncore.socket_map.values())
def log (self, *ignore):
pass
......
This diff is collapsed.
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