root / trunk / twisted / application / strports.py

Revision 24991, 6.8 kB (checked in by exarkun, 9 months ago)

Merge distrib-wantpid-2295-2

Author: exarkun
Reviewer: ralphm
Fixes: #2295

Add an optional parameter to the AF_FILE style of strport
description, lockfile. By default, a "unix:" strport
will attempt to acquire a lock associate with the socket
specified. If lockfile=0 is given, this behavior will
be disabled.

twisted.web.distrib is also changed to allow a strports
description for the port it listens on, allowing a lock
file to be used or not with the port it listens on.

Line 
1 # -*- test-case-name: twisted.test.test_strports -*-
2
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6 #
7 """
8 Port description language
9
10 This module implements a description mini-language for ports, and provides
11 functions to parse it and to use it to directly construct appropriate
12 network server services or to directly listen on them.
13
14 Here are some examples::
15  >>> s=service("80", server.Site())
16  >>> s=service("tcp:80", server.Site())
17  >>> s=service("tcp:80:interface=127.0.0.1", server.Site())
18  >>> s=service("ssl:443", server.Site())
19  >>> s=service("ssl:443:privateKey=mykey.pem", server.Site())
20  >>> s=service("ssl:443:privateKey=mykey.pem:certKey=cert.pem", server.Site())
21  >>> s=service("unix:/var/run/finger", FingerFactory())
22  >>> s=service("unix:/var/run/finger:mode=660", FingerFactory())
23  >>> p=listen("80", server.Site())
24  >>> p=listen("tcp:80", server.Site())
25  >>> p=listen("tcp:80:interface=127.0.0.1", server.Site())
26  >>> p=listen("ssl:443", server.Site())
27  >>> p=listen("ssl:443:privateKey=mykey.pem", server.Site())
28  >>> p=listen("ssl:443:privateKey=mykey.pem:certKey=cert.pem", server.Site())
29  >>> p=listen("unix:/var/run/finger", FingerFactory())
30  >>> p=listen("unix:/var/run/finger:mode=660", FingerFactory())
31  >>> p=listen("unix:/var/run/finger:lockfile=0", FingerFactory())
32
33 See specific function documentation for more information.
34
35 Maintainer: Moshe Zadka
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']
Note: See TracBrowser for help on using the browser.