Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / runner / inetdtap.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4
5
6 """
7 Twisted inetd TAP support
8
9 Maintainer: Andrew Bennetts
10
11 Future Plans: more configurability.
12 """
13
14 import os, pwd, grp, socket
15
16 from twisted.runner import inetd, inetdconf
17 from twisted.python import log, usage
18 from twisted.internet.protocol import ServerFactory
19 from twisted.application import internet, service as appservice
20
21 try:
22     import portmap
23     rpcOk = 1
24 except ImportError:
25     rpcOk = 0
26
27
28 # Protocol map
29 protocolDict = {'tcp': socket.IPPROTO_TCP, 'udp': socket.IPPROTO_UDP}
30
31
32 class Options(usage.Options):
33
34     optParameters = [
35         ['rpc', 'r', '/etc/rpc', 'RPC procedure table file'],
36         ['file', 'f', '/etc/inetd.conf', 'Service configuration file']
37     ]
38
39     optFlags = [['nointernal', 'i', "Don't run internal services"]]
40
41     compData = usage.Completions(
42         optActions={"file": usage.CompleteFiles('*.conf')}
43         )
44
45 class RPCServer(internet.TCPServer):
46
47     def __init__(self, rpcVersions, rpcConf, proto, service):
48         internet.TCPServer.__init__(0, ServerFactory())
49         self.rpcConf = rpcConf
50         self.proto = proto
51         self.service = service
52
53     def startService(self):
54         internet.TCPServer.startService(self)
55         import portmap
56         portNo = self._port.getHost()[2]
57         service = self.service
58         for version in rpcVersions:
59             portmap.set(self.rpcConf.services[name], version, self.proto,
60                         portNo)
61             inetd.forkPassingFD(service.program, service.programArgs,
62                                 os.environ, service.user, service.group, p)
63
64 def makeService(config):
65     s = appservice.MultiService()
66     conf = inetdconf.InetdConf()
67     conf.parseFile(open(config['file']))
68
69     rpcConf = inetdconf.RPCServicesConf()
70     try:
71         rpcConf.parseFile(open(config['rpc']))
72     except:
73         # We'll survive even if we can't read /etc/rpc
74         log.deferr()
75     
76     for service in conf.services:
77         rpc = service.protocol.startswith('rpc/')
78         protocol = service.protocol
79
80         if rpc and not rpcOk:
81             log.msg('Skipping rpc service due to lack of rpc support')
82             continue
83
84         if rpc:
85             # RPC has extra options, so extract that
86             protocol = protocol[4:]     # trim 'rpc/'
87             if not protocolDict.has_key(protocol):
88                 log.msg('Bad protocol: ' + protocol)
89                 continue
90             
91             try:
92                 name, rpcVersions = service.name.split('/')
93             except ValueError:
94                 log.msg('Bad RPC service/version: ' + service.name)
95                 continue
96
97             if not rpcConf.services.has_key(name):
98                 log.msg('Unknown RPC service: ' + repr(service.name))
99                 continue
100
101             try:
102                 if '-' in rpcVersions:
103                     start, end = map(int, rpcVersions.split('-'))
104                     rpcVersions = range(start, end+1)
105                 else:
106                     rpcVersions = [int(rpcVersions)]
107             except ValueError:
108                 log.msg('Bad RPC versions: ' + str(rpcVersions))
109                 continue
110             
111         if (protocol, service.socketType) not in [('tcp', 'stream'),
112                                                   ('udp', 'dgram')]:
113             log.msg('Skipping unsupported type/protocol: %s/%s'
114                     % (service.socketType, service.protocol))
115             continue
116
117         # Convert the username into a uid (if necessary)
118         try:
119             service.user = int(service.user)
120         except ValueError:
121             try:
122                 service.user = pwd.getpwnam(service.user)[2]
123             except KeyError:
124                 log.msg('Unknown user: ' + service.user)
125                 continue
126
127         # Convert the group name into a gid (if necessary)
128         if service.group is None:
129             # If no group was specified, use the user's primary group
130             service.group = pwd.getpwuid(service.user)[3]
131         else:
132             try:
133                 service.group = int(service.group)
134             except ValueError:
135                 try:
136                     service.group = grp.getgrnam(service.group)[2]
137                 except KeyError:
138                     log.msg('Unknown group: ' + service.group)
139                     continue
140
141         if service.program == 'internal':
142             if config['nointernal']:
143                 continue
144
145             # Internal services can use a standard ServerFactory
146             if not inetd.internalProtocols.has_key(service.name):
147                 log.msg('Unknown internal service: ' + service.name)
148                 continue
149             factory = ServerFactory()
150             factory.protocol = inetd.internalProtocols[service.name]
151         elif rpc:
152             i = RPCServer(rpcVersions, rpcConf, proto, service)
153             i.setServiceParent(s)
154             continue
155         else:
156             # Non-internal non-rpc services use InetdFactory
157             factory = inetd.InetdFactory(service)
158
159         if protocol == 'tcp':
160             internet.TCPServer(service.port, factory).setServiceParent(s)
161         elif protocol == 'udp':
162             raise RuntimeError("not supporting UDP")
163     return s