~midokura/nova/midostack-oneiric

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/application/strports.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_strports -*-
 
2
 
 
3
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
 
4
# See LICENSE for details.
 
5
 
 
6
"""
 
7
Port description language
 
8
 
 
9
This module implements a description mini-language for ports, and provides
 
10
functions to parse it and to use it to directly construct appropriate
 
11
network server services or to directly listen on them.
 
12
 
 
13
Here are some examples. They assume the following toy resource and factory
 
14
definitions::
 
15
    class Simple(resource.Resource):
 
16
        isLeaf = True
 
17
        def render_GET(self, request):
 
18
            return "<html>Hello, world!</html>"
 
19
 
 
20
     class FingerProtocol(protocol.Protocol):
 
21
         def connectionMade(self):
 
22
             self.transport.loseConnection()
 
23
 
 
24
     class FingerFactory(protocol.ServerFactory):
 
25
         protocol = FingerProtocol
 
26
 
 
27
Examples using SSL require a private key and a certificate. If a private key
 
28
file name (C{privateKey}) isn't provided, a "server.pem" file is assumed to
 
29
exist which contains the private key. If the certificate file name (C{certKey})
 
30
isn't provided, the private key file is assumed to contain the certificate as
 
31
well::
 
32
    >>> s=service("80", server.Site(Simple()))
 
33
    >>> s=service("tcp:80", server.Site(Simple()))
 
34
    >>> s=service("tcp:80:interface=127.0.0.1", server.Site(Simple()))
 
35
    >>> s=service("ssl:443", server.Site(Simple()))
 
36
    >>> s=service("ssl:443:privateKey=mykey.pem", server.Site(Simple()))
 
37
    >>> s=service("ssl:443:privateKey=mykey.pem:certKey=cert.pem", server.Site(Simple()))
 
38
    >>> s=service("unix:/var/run/finger", FingerFactory())
 
39
    >>> s=service("unix:/var/run/finger:mode=660", FingerFactory())
 
40
    >>> p=listen("80", server.Site(Simple()))
 
41
    >>> p=listen("tcp:80", server.Site(Simple()))
 
42
    >>> p=listen("tcp:80:interface=127.0.0.1", server.Site(Simple()))
 
43
    >>> p=listen("ssl:443", server.Site(Simple()))
 
44
    >>> p=listen("ssl:443:privateKey=mykey.pem", server.Site(Simple()))
 
45
    >>> p=listen("ssl:443:privateKey=mykey.pem:certKey=cert.pem", server.Site(Simple()))
 
46
    >>> p=listen("unix:/var/run/finger", FingerFactory())
 
47
    >>> p=listen("unix:/var/run/finger:mode=660", FingerFactory())
 
48
    >>> p=listen("unix:/var/run/finger:lockfile=0", FingerFactory())
 
49
 
 
50
See specific function documentation for more information.
 
51
 
 
52
Maintainer: Moshe Zadka
 
53
"""
 
54
from __future__ import generators
 
55
 
 
56
def _parseTCP(factory, port, interface="", backlog=50):
 
57
    return (int(port), factory), {'interface': interface,
 
58
                                  'backlog': int(backlog)}
 
59
 
 
60
 
 
61
 
 
62
def _parseUNIX(factory, address, mode='666', backlog=50, lockfile=True):
 
63
    return (
 
64
        (address, factory),
 
65
        {'mode': int(mode, 8), 'backlog': int(backlog),
 
66
         'wantPID': bool(int(lockfile))})
 
67
 
 
68
 
 
69
 
 
70
def _parseSSL(factory, port, privateKey="server.pem", certKey=None,
 
71
              sslmethod=None, interface='', backlog=50):
 
72
    from twisted.internet import ssl
 
73
    if certKey is None:
 
74
        certKey = privateKey
 
75
    kw = {}
 
76
    if sslmethod is not None:
 
77
        kw['sslmethod'] = getattr(ssl.SSL, sslmethod)
 
78
    cf = ssl.DefaultOpenSSLContextFactory(privateKey, certKey, **kw)
 
79
    return ((int(port), factory, cf),
 
80
            {'interface': interface, 'backlog': int(backlog)})
 
81
 
 
82
_funcs = {"tcp": _parseTCP,
 
83
          "unix": _parseUNIX,
 
84
          "ssl": _parseSSL}
 
85
 
 
86
_OP, _STRING = range(2)
 
87
def _tokenize(description):
 
88
    current = ''
 
89
    ops = ':='
 
90
    nextOps = {':': ':=', '=': ':'}
 
91
    description = iter(description)
 
92
    for n in description:
 
93
        if n in ops:
 
94
            yield _STRING, current
 
95
            yield _OP, n
 
96
            current = ''
 
97
            ops = nextOps[n]
 
98
        elif n=='\\':
 
99
            current += description.next()
 
100
        else:
 
101
            current += n
 
102
    yield _STRING, current
 
103
 
 
104
def _parse(description):
 
105
    args, kw = [], {}
 
106
    def add(sofar):
 
107
        if len(sofar)==1:
 
108
            args.append(sofar[0])
 
109
        else:
 
110
            kw[sofar[0]] = sofar[1]
 
111
    sofar = ()
 
112
    for (type, value) in _tokenize(description):
 
113
        if type is _STRING:
 
114
            sofar += (value,)
 
115
        elif value==':':
 
116
            add(sofar)
 
117
            sofar = ()
 
118
    add(sofar)
 
119
    return args, kw
 
120
 
 
121
def parse(description, factory, default=None):
 
122
    """
 
123
    Parse the description of a reliable virtual circuit server (that is, a
 
124
    TCP port, a UNIX domain socket or an SSL port) and return the data
 
125
    necessary to call the reactor methods to listen on the given socket with
 
126
    the given factory.
 
127
 
 
128
    An argument with no colons means a default port. Usually the default
 
129
    type is C{tcp}, but passing a non-C{None} value as C{default} will set
 
130
    that as the default. Otherwise, it is a colon-separated string.  The
 
131
    first part means the type -- currently, it can only be ssl, unix or tcp.
 
132
    After that, comes a list of arguments. Arguments can be positional or
 
133
    keyword, and can be mixed.  Keyword arguments are indicated by
 
134
    C{'name=value'}. If a value is supposed to contain a C{':'}, a C{'='} or
 
135
    a C{'\\'}, escape it with a C{'\\'}.
 
136
 
 
137
    For TCP, the arguments are the port (port number) and, optionally the
 
138
    interface (interface on which to listen) and backlog (how many clients
 
139
    to keep in the backlog).
 
140
 
 
141
    For UNIX domain sockets, the arguments are address (the file name of the
 
142
    socket) and optionally the mode (the mode bits of the file, as an octal
 
143
    number) and the backlog (how many clients to keep in the backlog).
 
144
 
 
145
    For SSL sockets, the arguments are the port (port number) and,
 
146
    optionally, the privateKey (file in which the private key is in),
 
147
    certKey (file in which the certification is in), sslmethod (the name of
 
148
    the SSL method to allow), the interface (interface on which to listen)
 
149
    and the backlog (how many clients to keep in the backlog).
 
150
 
 
151
    @type description: C{str}
 
152
    @type factory: L{twisted.internet.interfaces.IProtocolFactory}
 
153
    @type default: C{str} or C{None}
 
154
    @rtype: C{tuple}
 
155
    @return: a tuple of string, tuple and dictionary. The string is the name
 
156
    of the method (sans C{'listen'}) to call, and the tuple and dictionary
 
157
    are the arguments and keyword arguments to the method.
 
158
    @raises ValueError: if the string is formatted incorrectly.
 
159
    @raises KeyError: if the type is other than unix, ssl or tcp.
 
160
    """
 
161
    args, kw = _parse(description)
 
162
    if not args or (len(args)==1 and not kw):
 
163
        args[0:0] = [default or 'tcp']
 
164
    return (args[0].upper(),)+_funcs[args[0]](factory, *args[1:], **kw)
 
165
 
 
166
def service(description, factory, default=None):
 
167
    """Return the service 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.application.service.IService}
 
173
    @return: the service 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.application import internet
 
180
    name, args, kw = parse(description, factory, default)
 
181
    return getattr(internet, name+'Server')(*args, **kw)
 
182
 
 
183
def listen(description, factory, default=None):
 
184
    """Listen on a port corresponding to a description
 
185
 
 
186
    @type description: C{str}
 
187
    @type factory: L{twisted.internet.interfaces.IProtocolFactory}
 
188
    @type default: C{str} or C{None}
 
189
    @rtype: C{twisted.internet.interfaces.IListeningPort}
 
190
    @return: the port corresponding to a description of a reliable
 
191
    virtual circuit server.
 
192
 
 
193
    See the documentation of the C{parse} function for description
 
194
    of the semantics of the arguments.
 
195
    """
 
196
    from twisted.internet import reactor
 
197
    name, args, kw = parse(description, factory, default)
 
198
    return getattr(reactor, 'listen'+name)(*args, **kw)
 
199
 
 
200
__all__ = ['parse', 'service', 'listen']