[Subversion] / PEAK / src / peak / net / sockets.py  

View of /PEAK/src/peak/net/sockets.py

Parent Directory | Revision Log
Revision: 2047 - (download) (as text)
Sat Apr 23 19:40:35 2005 UTC (19 years ago) by pje
File size: 5753 byte(s)
Fix missing '.errno', as reported by Alain Poirier.
from protocols import Interface, Attribute
from peak.api import *
from interfaces import *
import sys, socket

def getConstants(module,prefix):
    p = len(prefix)
    d = module.__dict__
    return [(k[p:].lower(),v) for k,v in d.items() if k.startswith(prefix)]


class SocketFamily(model.ExtendedEnum):

    __values = model.enumDict( getConstants(socket,'AF_') )


class SocketType(model.ExtendedEnum):

    __values = model.enumDict( getConstants(socket, 'SOCK_') )


class SocketProtocol(model.ExtendedEnum):

    __values = model.enumDict( getConstants(socket, 'IPPROTO_') )

    def _convert(klass,x):
        try:
            return int(x)
        except ValueError:
            return socket.getprotobyname(x)

    _convert = classmethod(_convert)


class FileDescriptor(model.ExtendedEnum):

    stdin = model.enum(0)
    stdout = model.enum(1)
    stderr = model.enum(2)


class socketURL(naming.URL.Base):

    def listen_sockets(self, maxsocks=sys.maxint):
        sockets = []

        for res in self.listen_addrs():
            af, socktype, proto, canonname, sa = res
            try:
                s = socket.socket(af, socktype, proto)
                if 'unix' in SocketFamily and af==SocketFamily.unix:
                    import os,errno
                    try:
                        os.unlink(sa)   # remove the existing unix socket
                    except OSError,v:
                        if v.errno<>errno.ENOENT: # ignore if socket doesn't exist
                            raise
                s.bind(sa)
                s.listen(5) # should will be made configurable
                sockets.append(s)
                if len(sockets) >= maxsocks:
                    break
            except socket.error, msg:
                pass

        if not sockets:
            raise socket.error, msg

        return sockets













class tcpudpURL(socketURL):

    protocols.advise(
        instancesProvide = [IClientSocketAddr, IListenSocketAddr]
    )

    supportedSchemes = {
        'tcp' : socket.SOCK_STREAM,
        'udp' : socket.SOCK_DGRAM
    }

    class host(naming.URL.RequiredField): pass

    class port(naming.URL.Field): pass

    syntax = naming.URL.Sequence(
        '//', host, (':', port), ('/',)
    )

    def connect_addrs(self):
        return socket.getaddrinfo(self.host, self.port,
            0, self.supportedSchemes[self.scheme])

    def listen_addrs(self):
        host = self.host
        if not host or host == '*':
            host = None

        return socket.getaddrinfo(host, self.port,
            0, self.supportedSchemes[self.scheme], 0, socket.AI_PASSIVE)











class unixURL(socketURL):

    protocols.advise(
        instancesProvide = [IClientSocketAddr, IListenSocketAddr]
    )

    supportedSchemes = {
        'unix' : socket.SOCK_STREAM,
        'unix.dg' : socket.SOCK_DGRAM
    }

    class path(naming.URL.RequiredField): pass

    syntax = naming.URL.Sequence(path)

    def connect_addrs(self):
        return [
            (socket.AF_UNIX, self.supportedSchemes[self.scheme], 0, None, self.path)
        ]

    listen_addrs = connect_addrs




















def ClientConnect(addr):
    """Attempt to connect to an IClientSocketAddr"""

    sock = None
    for res in addr.connect_addrs():
        af, socktype, proto, canonname, sa = res
        try:
            sock = socket.socket(af, socktype, proto)
            sock.connect(sa)
        except socket.error, msg:
            if sock:
                sock.close()
            sock = None
            continue
        break

    if sock is None:
        raise socket.error, msg

    return sock



protocols.declareAdapter(
    ClientConnect,
    provides=[IClientSocket],
    forProtocols=[IClientSocketAddr]
)


protocols.declareAdapter(
    lambda o: o.listen_sockets(maxsocks=1)[0],
    provides=[IListeningSocket],
    forProtocols=[IListenSocketAddr]
)






class fdURL(naming.URL.Base):

    """fd.socket:fileno[/family[/kind[/protocol]]]

    'fileno' can be an integer, or one of 'stdin', 'stdout', 'stderr'

    'family' can be the lowercase form of any 'socket.AF_*' constant, e.g.
    'unix', 'inet', 'inet6', etc.  ('inet' is the default if unspecified.)

    'kind' can be the lowercase form of any 'socket.SOCK_*' constant, e.g.
    'stream', 'dgram', 'raw', etc.  ('stream' is the default if unspecified.)

    'protocol' can be an integer, or the lowercase form of any
    'socket.IPPROTO_*' constant, e.g. 'ip', 'icmp', 'udp', etc.  It can also
    be the name of a protocol that will be looked up using
    'socket.getprotobyname()'.  (If unspecified, it defaults to the
    system-defined default protocol for the family and kind; effectively this
    is the same as 'SocketProtocol.ip'.)

    Example::

        fd.socket:stdin/inet6/dgram/udp
    """

    supportedSchemes = 'fd','fd.socket'

    class fileno(naming.URL.Field):
        referencedType = FileDescriptor

    class family(naming.URL.Field):
        referencedType = SocketFamily
        defaultValue   = SocketFamily.inet
        canBeEmpty     = True

    class kind(naming.URL.Field):
        referencedType = SocketType
        defaultValue   = SocketType.stream
        canBeEmpty     = True



    class protocol(naming.URL.Field):
        referencedType = SocketProtocol
        defaultValue   = SocketProtocol.ip
        canBeEmpty     = True

    syntax = naming.URL.Sequence(
        fileno, ( '/', family, ('/', kind, ('/', protocol)))
    )

    def asSocket(self):
        return socket.fromfd(self.fileno, self.family, self.kind, self.protocol)


protocols.declareAdapter(
    lambda o: o.asSocket(),
    provides=[IClientSocket,IListeningSocket],
    forTypes=[fdURL]
)
























cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help