| 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 |
from __future__ import generators |
|---|
| 38 |
|
|---|
| 39 |
def _parseTCP(factory, port, interface="", backlog=50): |
|---|
| 40 |
return (int(port), factory), {'interface': interface, |
|---|
| 41 |
'backlog': int(backlog)} |
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
def _parseUNIX(factory, address, mode='666', backlog=50, lockfile=True): |
|---|
| 46 |
return ( |
|---|
| 47 |
(address, factory), |
|---|
| 48 |
{'mode': int(mode, 8), 'backlog': int(backlog), |
|---|
| 49 |
'wantPID': bool(int(lockfile))}) |
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 |
def _parseSSL(factory, port, privateKey="server.pem", certKey=None, |
|---|
| 54 |
sslmethod=None, interface='', backlog=50): |
|---|
| 55 |
from twisted.internet import ssl |
|---|
| 56 |
if certKey is None: |
|---|
| 57 |
certKey = privateKey |
|---|
| 58 |
kw = {} |
|---|
| 59 |
if sslmethod is not None: |
|---|
| 60 |
kw['sslmethod'] = getattr(ssl.SSL, sslmethod) |
|---|
| 61 |
cf = ssl.DefaultOpenSSLContextFactory(privateKey, certKey, **kw) |
|---|
| 62 |
return ((int(port), factory, cf), |
|---|
| 63 |
{'interface': interface, 'backlog': int(backlog)}) |
|---|
| 64 |
|
|---|
| 65 |
_funcs = {"tcp": _parseTCP, |
|---|
| 66 |
"unix": _parseUNIX, |
|---|
| 67 |
"ssl": _parseSSL} |
|---|
| 68 |
|
|---|
| 69 |
_OP, _STRING = range(2) |
|---|
| 70 |
def _tokenize(description): |
|---|
| 71 |
current = '' |
|---|
| 72 |
ops = ':=' |
|---|
| 73 |
nextOps = {':': ':=', '=': ':'} |
|---|
| 74 |
description = iter(description) |
|---|
| 75 |
for n in description: |
|---|
| 76 |
if n in ops: |
|---|
| 77 |
yield _STRING, current |
|---|
| 78 |
yield _OP, n |
|---|
| 79 |
current = '' |
|---|
| 80 |
ops = nextOps[n] |
|---|
| 81 |
elif n=='\\': |
|---|
| 82 |
current += description.next() |
|---|
| 83 |
else: |
|---|
| 84 |
current += n |
|---|
| 85 |
yield _STRING, current |
|---|
| 86 |
|
|---|
| 87 |
def _parse(description): |
|---|
| 88 |
args, kw = [], {} |
|---|
| 89 |
def add(sofar): |
|---|
| 90 |
if len(sofar)==1: |
|---|
| 91 |
args.append(sofar[0]) |
|---|
| 92 |
else: |
|---|
| 93 |
kw[sofar[0]] = sofar[1] |
|---|
| 94 |
sofar = () |
|---|
| 95 |
for (type, value) in _tokenize(description): |
|---|
| 96 |
if type is _STRING: |
|---|
| 97 |
sofar += (value,) |
|---|
| 98 |
elif value==':': |
|---|
| 99 |
add(sofar) |
|---|
| 100 |
sofar = () |
|---|
| 101 |
add(sofar) |
|---|
| 102 |
return args, kw |
|---|
| 103 |
|
|---|
| 104 |
def parse(description, factory, default=None): |
|---|
| 105 |
""" |
|---|
| 106 |
Parse the description of a reliable virtual circuit server (that is, a |
|---|
| 107 |
TCP port, a UNIX domain socket or an SSL port) and return the data |
|---|
| 108 |
necessary to call the reactor methods to listen on the given socket with |
|---|
| 109 |
the given factory. |
|---|
| 110 |
|
|---|
| 111 |
An argument with no colons means a default port. Usually the default |
|---|
| 112 |
type is C{tcp}, but passing a non-C{None} value as C{default} will set |
|---|
| 113 |
that as the default. Otherwise, it is a colon-separated string. The |
|---|
| 114 |
first part means the type -- currently, it can only be ssl, unix or tcp. |
|---|
| 115 |
After that, comes a list of arguments. Arguments can be positional or |
|---|
| 116 |
keyword, and can be mixed. Keyword arguments are indicated by |
|---|
| 117 |
C{'name=value'}. If a value is supposed to contain a C{':'}, a C{'='} or |
|---|
| 118 |
a C{'\\'}, escape it with a C{'\\'}. |
|---|
| 119 |
|
|---|
| 120 |
For TCP, the arguments are the port (port number) and, optionally the |
|---|
| 121 |
interface (interface on which to listen) and backlog (how many clients |
|---|
| 122 |
to keep in the backlog). |
|---|
| 123 |
|
|---|
| 124 |
For UNIX domain sockets, the arguments are address (the file name of the |
|---|
| 125 |
socket) and optionally the mode (the mode bits of the file, as an octal |
|---|
| 126 |
number) and the backlog (how many clients to keep in the backlog). |
|---|
| 127 |
|
|---|
| 128 |
For SSL sockets, the arguments are the port (port number) and, |
|---|
| 129 |
optionally, the privateKey (file in which the private key is in), |
|---|
| 130 |
certKey (file in which the certification is in), sslmethod (the name of |
|---|
| 131 |
the SSL method to allow), the interface (interface on which to listen) |
|---|
| 132 |
and the backlog (how many clients to keep in the backlog). |
|---|
| 133 |
|
|---|
| 134 |
@type description: C{str} |
|---|
| 135 |
@type factory: L{twisted.internet.interfaces.IProtocolFactory} |
|---|
| 136 |
@type default: C{str} or C{None} |
|---|
| 137 |
@rtype: C{tuple} |
|---|
| 138 |
@return: a tuple of string, tuple and dictionary. The string is the name |
|---|
| 139 |
of the method (sans C{'listen'}) to call, and the tuple and dictionary |
|---|
| 140 |
are the arguments and keyword arguments to the method. |
|---|
| 141 |
@raises ValueError: if the string is formatted incorrectly. |
|---|
| 142 |
@raises KeyError: if the type is other than unix, ssl or tcp. |
|---|
| 143 |
""" |
|---|
| 144 |
args, kw = _parse(description) |
|---|
| 145 |
if not args or (len(args)==1 and not kw): |
|---|
| 146 |
args[0:0] = [default or 'tcp'] |
|---|
| 147 |
return (args[0].upper(),)+_funcs[args[0]](factory, *args[1:], **kw) |
|---|
| 148 |
|
|---|
| 149 |
def service(description, factory, default=None): |
|---|
| 150 |
"""Return the service corresponding to a description |
|---|
| 151 |
|
|---|
| 152 |
@type description: C{str} |
|---|
| 153 |
@type factory: L{twisted.internet.interfaces.IProtocolFactory} |
|---|
| 154 |
@type default: C{str} or C{None} |
|---|
| 155 |
@rtype: C{twisted.application.service.IService} |
|---|
| 156 |
@return: the service corresponding to a description of a reliable |
|---|
| 157 |
virtual circuit server. |
|---|
| 158 |
|
|---|
| 159 |
See the documentation of the C{parse} function for description |
|---|
| 160 |
of the semantics of the arguments. |
|---|
| 161 |
""" |
|---|
| 162 |
from twisted.application import internet |
|---|
| 163 |
name, args, kw = parse(description, factory, default) |
|---|
| 164 |
return getattr(internet, name+'Server')(*args, **kw) |
|---|
| 165 |
|
|---|
| 166 |
def listen(description, factory, default=None): |
|---|
| 167 |
"""Listen on a port corresponding to a description |
|---|
| 168 |
|
|---|
| 169 |
@type description: C{str} |
|---|
| 170 |
@type factory: L{twisted.internet.interfaces.IProtocolFactory} |
|---|
| 171 |
@type default: C{str} or C{None} |
|---|
| 172 |
@rtype: C{twisted.internet.interfaces.IListeningPort} |
|---|
| 173 |
@return: the port corresponding to a description of a reliable |
|---|
| 174 |
virtual circuit server. |
|---|
| 175 |
|
|---|
| 176 |
See the documentation of the C{parse} function for description |
|---|
| 177 |
of the semantics of the arguments. |
|---|
| 178 |
""" |
|---|
| 179 |
from twisted.internet import reactor |
|---|
| 180 |
name, args, kw = parse(description, factory, default) |
|---|
| 181 |
return getattr(reactor, 'listen'+name)(*args, **kw) |
|---|
| 182 |
|
|---|
| 183 |
__all__ = ['parse', 'service', 'listen'] |
|---|