1
# -*- test-case-name: twisted.test.test_strports -*-
3
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
4
# See LICENSE for details.
7
Port description language
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.
13
Here are some examples. They assume the following toy resource and factory
15
class Simple(resource.Resource):
17
def render_GET(self, request):
18
return "<html>Hello, world!</html>"
20
class FingerProtocol(protocol.Protocol):
21
def connectionMade(self):
22
self.transport.loseConnection()
24
class FingerFactory(protocol.ServerFactory):
25
protocol = FingerProtocol
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
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())
50
See specific function documentation for more information.
52
Maintainer: Moshe Zadka
54
from __future__ import generators
56
def _parseTCP(factory, port, interface="", backlog=50):
57
return (int(port), factory), {'interface': interface,
58
'backlog': int(backlog)}
62
def _parseUNIX(factory, address, mode='666', backlog=50, lockfile=True):
65
{'mode': int(mode, 8), 'backlog': int(backlog),
66
'wantPID': bool(int(lockfile))})
70
def _parseSSL(factory, port, privateKey="server.pem", certKey=None,
71
sslmethod=None, interface='', backlog=50):
72
from twisted.internet import ssl
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)})
82
_funcs = {"tcp": _parseTCP,
86
_OP, _STRING = range(2)
87
def _tokenize(description):
90
nextOps = {':': ':=', '=': ':'}
91
description = iter(description)
94
yield _STRING, current
99
current += description.next()
102
yield _STRING, current
104
def _parse(description):
108
args.append(sofar[0])
110
kw[sofar[0]] = sofar[1]
112
for (type, value) in _tokenize(description):
121
def parse(description, factory, default=None):
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
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{'\\'}.
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).
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).
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).
151
@type description: C{str}
152
@type factory: L{twisted.internet.interfaces.IProtocolFactory}
153
@type default: C{str} or C{None}
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.
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)
166
def service(description, factory, default=None):
167
"""Return the service corresponding to a description
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.
176
See the documentation of the C{parse} function for description
177
of the semantics of the arguments.
179
from twisted.application import internet
180
name, args, kw = parse(description, factory, default)
181
return getattr(internet, name+'Server')(*args, **kw)
183
def listen(description, factory, default=None):
184
"""Listen on a port corresponding to a description
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.
193
See the documentation of the C{parse} function for description
194
of the semantics of the arguments.
196
from twisted.internet import reactor
197
name, args, kw = parse(description, factory, default)
198
return getattr(reactor, 'listen'+name)(*args, **kw)
200
__all__ = ['parse', 'service', 'listen']