1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
7 Twisted inetd TAP support
9 Maintainer: Andrew Bennetts
11 Future Plans: more configurability.
14 import os, pwd, grp, socket
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
29 protocolDict = {'tcp': socket.IPPROTO_TCP, 'udp': socket.IPPROTO_UDP}
32 class Options(usage.Options):
35 ['rpc', 'r', '/etc/rpc', 'RPC procedure table file'],
36 ['file', 'f', '/etc/inetd.conf', 'Service configuration file']
39 optFlags = [['nointernal', 'i', "Don't run internal services"]]
41 compData = usage.Completions(
42 optActions={"file": usage.CompleteFiles('*.conf')}
45 class RPCServer(internet.TCPServer):
47 def __init__(self, rpcVersions, rpcConf, proto, service):
48 internet.TCPServer.__init__(0, ServerFactory())
49 self.rpcConf = rpcConf
51 self.service = service
53 def startService(self):
54 internet.TCPServer.startService(self)
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,
61 inetd.forkPassingFD(service.program, service.programArgs,
62 os.environ, service.user, service.group, p)
64 def makeService(config):
65 s = appservice.MultiService()
66 conf = inetdconf.InetdConf()
67 conf.parseFile(open(config['file']))
69 rpcConf = inetdconf.RPCServicesConf()
71 rpcConf.parseFile(open(config['rpc']))
73 # We'll survive even if we can't read /etc/rpc
76 for service in conf.services:
77 rpc = service.protocol.startswith('rpc/')
78 protocol = service.protocol
81 log.msg('Skipping rpc service due to lack of rpc support')
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)
92 name, rpcVersions = service.name.split('/')
94 log.msg('Bad RPC service/version: ' + service.name)
97 if not rpcConf.services.has_key(name):
98 log.msg('Unknown RPC service: ' + repr(service.name))
102 if '-' in rpcVersions:
103 start, end = map(int, rpcVersions.split('-'))
104 rpcVersions = range(start, end+1)
106 rpcVersions = [int(rpcVersions)]
108 log.msg('Bad RPC versions: ' + str(rpcVersions))
111 if (protocol, service.socketType) not in [('tcp', 'stream'),
113 log.msg('Skipping unsupported type/protocol: %s/%s'
114 % (service.socketType, service.protocol))
117 # Convert the username into a uid (if necessary)
119 service.user = int(service.user)
122 service.user = pwd.getpwnam(service.user)[2]
124 log.msg('Unknown user: ' + service.user)
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]
133 service.group = int(service.group)
136 service.group = grp.getgrnam(service.group)[2]
138 log.msg('Unknown group: ' + service.group)
141 if service.program == 'internal':
142 if config['nointernal']:
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)
149 factory = ServerFactory()
150 factory.protocol = inetd.internalProtocols[service.name]
152 i = RPCServer(rpcVersions, rpcConf, proto, service)
153 i.setServiceParent(s)
156 # Non-internal non-rpc services use InetdFactory
157 factory = inetd.InetdFactory(service)
159 if protocol == 'tcp':
160 internet.TCPServer(service.port, factory).setServiceParent(s)
161 elif protocol == 'udp':
162 raise RuntimeError("not supporting UDP")