| #!/usr/bin/env python |
| # Copyright 2011 Google Inc. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # TR-069 has mandatory attribute names that don't comply with policy |
| # pylint:disable=invalid-name |
| # |
| """The main server process for our TR-069 CPE device.""" |
| |
| __author__ = 'apenwarr@google.com (Avery Pennarun)' |
| |
| # this needs to be first, before any tornado imports |
| import tr.epoll_fix # pylint:disable=g-bad-import-order |
| |
| import errno |
| import os.path |
| import sys |
| import google3 |
| import bup.options |
| import diagui.main |
| import dm_root |
| import factory |
| import tr.acs_config |
| import tr.api |
| import tr.cwmptypes |
| import tr.filenotifier |
| import tr.handle |
| import tr.http |
| import tr.mainloop |
| import tr.rcommand |
| |
| |
| optspec = """ |
| cwmpd [options] |
| -- |
| r,rcmd-port= TCP port to listen for rcommands on; 0 to disable [12999] |
| u,unix-path= Unix socket to listen on [/tmp/cwmpd.sock] |
| i,ip= IP address to report to ACS. (default=finds interface IP address) |
| l,listenip= IP address to listen on [::1] |
| p,port= TCP port to listen for TR-069 on [7547] |
| ping-path= Force CPE ping listener to this URL path (default=random) |
| acs-url= URL of the TR-069 ACS server to connect to |
| fake-acs Run a fake ACS (and auto-set --acs-url to that) |
| no-cpe Don't run a CPE (and thus never connect to ACS) |
| cpe-listener Let CPE listen for http requests (not TR-069 compliant) |
| platform= Activate the platform-specific device tree (see platform/ dir) |
| ext-dir= Activate any extension modules in this dir [%(ext_dir)s] |
| close-stdio Close stdout after listeners are running; exit when stdin closes |
| ca-certs= SSL ca_certificates.crt file to use |
| client-cert= SSL client certificate to use |
| client-key= SSL client private key to use |
| restrict-acs-hosts= Domain names allowed for ACS URL. Default=unrestricted. Example: 'google.com gfsvc.com' |
| diagui Listen for diagui requests on diagui-port |
| diagui-port= Port to listen on (0=random) [80] |
| techui Also handle TechUI requests on the diagui-port |
| licenseui Listen for license requests on the diagui-port |
| factory Listen for factory requests on factory-port |
| factory-port= Port to listen on (0=random) [8883] |
| """ |
| |
| |
| def _GotData(loop, fd, unused_flags): |
| if not os.read(fd, 1024): |
| loop.ioloop.stop() |
| |
| |
| def main(): |
| try: |
| os.mkdir(tr.acs_config.CWMP_TMP_DIR) |
| except OSError, e: |
| if e.errno == errno.EEXIST: |
| pass |
| else: |
| raise |
| cwmpdir = os.path.dirname(os.path.abspath(sys.argv[0])) |
| defargs = dict(ext_dir=os.environ.get('CWMPD_EXT_DIR', cwmpdir + '/ext')) |
| o = bup.options.Options(optspec % defargs) |
| (opt, unused_flags, unused_extra) = o.parse(sys.argv[1:]) |
| |
| if not opt.platform: |
| o.fatal('You must specify a --platform') |
| |
| loop = tr.mainloop.MainLoop() |
| root = dm_root.DeviceModelRoot(loop, opt.platform, opt.ext_dir) |
| root.add_cwmp_extensions() |
| handle = root.handle |
| notifier = tr.filenotifier.FileNotifier(loop) |
| tr.cwmptypes.SetFileBackedNotifier(notifier) |
| acs = cpe = None |
| |
| if opt.fake_acs: |
| if not opt.port: |
| o.fatal("Can't use --fake-acs without --port") |
| acs = tr.api.ACS() |
| if not opt.acs_url: |
| opt.acs_url = 'http://localhost:%d/acs' % opt.port |
| if opt.cpe: |
| cpe = tr.api.CPE(handle) |
| if not opt.cpe_listener: |
| print 'CPE API is client mode only.' |
| |
| if cpe: |
| # Arguments to pass to Tornado HTTPClient.fetch |
| fetch_args = {'user_agent': 'catawampus-tr69'} |
| if opt.ca_certs: |
| fetch_args['ca_certs'] = opt.ca_certs |
| fetch_args['validate_cert'] = True |
| if opt.client_cert and opt.client_key: |
| fetch_args['client_cert'] = opt.client_cert |
| fetch_args['client_key'] = opt.client_key |
| |
| pc = root.get_platform_config(ioloop=loop.ioloop) |
| cpe.download_manager.SetDirectories(config_dir=pc.ConfigDir(), |
| download_dir=pc.DownloadDir()) |
| cpe_machine = tr.http.Listen(ip=opt.ip, port=opt.port, |
| ping_path=opt.ping_path, |
| acs=acs, cpe=cpe, |
| restrict_acs_hosts=opt.restrict_acs_hosts, |
| cpe_listener=opt.cpe_listener, |
| acs_config=tr.acs_config.AcsConfig(), |
| acs_url=opt.acs_url, |
| fetch_args=fetch_args) |
| ms = cpe_machine.GetManagementServer() |
| root.add_management_server(ms) |
| root.configure_tr157(cpe_machine) |
| else: |
| cpe_machine = None |
| |
| if opt.rcmd_port: |
| loop.ListenInet((opt.listenip, opt.rcmd_port), |
| tr.rcommand.MakeRemoteCommandStreamer(handle, cpe_machine)) |
| if opt.unix_path: |
| loop.ListenUnix(opt.unix_path, |
| tr.rcommand.MakeRemoteCommandStreamer(handle, cpe_machine)) |
| if opt.diagui or opt.licenseui: |
| inst = diagui.main.MainApplication(root, cpe_machine, |
| run_diagui=opt.diagui, |
| run_techui=opt.techui, |
| run_licenseui=opt.licenseui) |
| print 'Listening for diagui on port %d' % (opt.diagui_port,) |
| inst.listen(opt.diagui_port) |
| if opt.factory: |
| print 'Listening for factoryui on port %d' % (opt.factory_port,) |
| inst = factory.FactoryFactory() |
| inst.listen(opt.factory_port) |
| |
| if cpe_machine: |
| cpe_machine.Startup() |
| |
| if opt.close_stdio: |
| nullf = open('/dev/null', 'w+') |
| os.dup2(nullf.fileno(), 1) |
| nullf.close() |
| loop.ioloop.add_handler(sys.stdin.fileno(), |
| lambda *args: _GotData(loop, *args), |
| loop.ioloop.READ) |
| |
| loop.Start() |
| |
| |
| if __name__ == '__main__': |
| sys.stdout.flush() |
| sys.stdout = os.fdopen(1, 'w', 1) # force line buffering even if redirected |
| sys.stderr.flush() |
| sys.stderr = os.fdopen(2, 'w', 1) # force line buffering even if redirected |
| print |
| main() |