xref: /aosp_15_r20/external/curl/tests/negtelnetserver.py (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6236dae4SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
3*6236dae4SAndroid Build Coastguard Worker#
4*6236dae4SAndroid Build Coastguard Worker#  Project                     ___| | | |  _ \| |
5*6236dae4SAndroid Build Coastguard Worker#                             / __| | | | |_) | |
6*6236dae4SAndroid Build Coastguard Worker#                            | (__| |_| |  _ <| |___
7*6236dae4SAndroid Build Coastguard Worker#                             \___|\___/|_| \_\_____|
8*6236dae4SAndroid Build Coastguard Worker#
9*6236dae4SAndroid Build Coastguard Worker# Copyright (C) Daniel Stenberg, <[email protected]>, et al.
10*6236dae4SAndroid Build Coastguard Worker#
11*6236dae4SAndroid Build Coastguard Worker# This software is licensed as described in the file COPYING, which
12*6236dae4SAndroid Build Coastguard Worker# you should have received as part of this distribution. The terms
13*6236dae4SAndroid Build Coastguard Worker# are also available at https://curl.se/docs/copyright.html.
14*6236dae4SAndroid Build Coastguard Worker#
15*6236dae4SAndroid Build Coastguard Worker# You may opt to use, copy, modify, merge, publish, distribute and/or sell
16*6236dae4SAndroid Build Coastguard Worker# copies of the Software, and permit persons to whom the Software is
17*6236dae4SAndroid Build Coastguard Worker# furnished to do so, under the terms of the COPYING file.
18*6236dae4SAndroid Build Coastguard Worker#
19*6236dae4SAndroid Build Coastguard Worker# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20*6236dae4SAndroid Build Coastguard Worker# KIND, either express or implied.
21*6236dae4SAndroid Build Coastguard Worker#
22*6236dae4SAndroid Build Coastguard Worker# SPDX-License-Identifier: curl
23*6236dae4SAndroid Build Coastguard Worker#
24*6236dae4SAndroid Build Coastguard Worker"""A telnet server which negotiates."""
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Workerfrom __future__ import (absolute_import, division, print_function,
27*6236dae4SAndroid Build Coastguard Worker                        unicode_literals)
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Workerimport argparse
30*6236dae4SAndroid Build Coastguard Workerimport logging
31*6236dae4SAndroid Build Coastguard Workerimport os
32*6236dae4SAndroid Build Coastguard Workerimport socket
33*6236dae4SAndroid Build Coastguard Workerimport sys
34*6236dae4SAndroid Build Coastguard Worker
35*6236dae4SAndroid Build Coastguard Workerfrom util import ClosingFileHandler
36*6236dae4SAndroid Build Coastguard Worker
37*6236dae4SAndroid Build Coastguard Workerif sys.version_info.major >= 3:
38*6236dae4SAndroid Build Coastguard Worker    import socketserver
39*6236dae4SAndroid Build Coastguard Workerelse:
40*6236dae4SAndroid Build Coastguard Worker    import SocketServer as socketserver
41*6236dae4SAndroid Build Coastguard Worker
42*6236dae4SAndroid Build Coastguard Workerlog = logging.getLogger(__name__)
43*6236dae4SAndroid Build Coastguard WorkerHOST = "localhost"
44*6236dae4SAndroid Build Coastguard WorkerIDENT = "NTEL"
45*6236dae4SAndroid Build Coastguard Worker
46*6236dae4SAndroid Build Coastguard Worker
47*6236dae4SAndroid Build Coastguard Worker# The strings that indicate the test framework is checking our aliveness
48*6236dae4SAndroid Build Coastguard WorkerVERIFIED_REQ = "verifiedserver"
49*6236dae4SAndroid Build Coastguard WorkerVERIFIED_RSP = "WE ROOLZ: {pid}"
50*6236dae4SAndroid Build Coastguard Worker
51*6236dae4SAndroid Build Coastguard Worker
52*6236dae4SAndroid Build Coastguard Workerdef telnetserver(options):
53*6236dae4SAndroid Build Coastguard Worker    """Start up a TCP server with a telnet handler and serve DICT requests forever."""
54*6236dae4SAndroid Build Coastguard Worker    if options.pidfile:
55*6236dae4SAndroid Build Coastguard Worker        pid = os.getpid()
56*6236dae4SAndroid Build Coastguard Worker        # see tests/server/util.c function write_pidfile
57*6236dae4SAndroid Build Coastguard Worker        if os.name == "nt":
58*6236dae4SAndroid Build Coastguard Worker            pid += 65536
59*6236dae4SAndroid Build Coastguard Worker        with open(options.pidfile, "w") as f:
60*6236dae4SAndroid Build Coastguard Worker            f.write(str(pid))
61*6236dae4SAndroid Build Coastguard Worker
62*6236dae4SAndroid Build Coastguard Worker    local_bind = (HOST, options.port)
63*6236dae4SAndroid Build Coastguard Worker    log.info("Listening on %s", local_bind)
64*6236dae4SAndroid Build Coastguard Worker
65*6236dae4SAndroid Build Coastguard Worker    # Need to set the allow_reuse on the class, not on the instance.
66*6236dae4SAndroid Build Coastguard Worker    socketserver.TCPServer.allow_reuse_address = True
67*6236dae4SAndroid Build Coastguard Worker    with socketserver.TCPServer(local_bind, NegotiatingTelnetHandler) as server:
68*6236dae4SAndroid Build Coastguard Worker        server.serve_forever()
69*6236dae4SAndroid Build Coastguard Worker    # leaving `with` calls server.close() automatically
70*6236dae4SAndroid Build Coastguard Worker    return ScriptRC.SUCCESS
71*6236dae4SAndroid Build Coastguard Worker
72*6236dae4SAndroid Build Coastguard Worker
73*6236dae4SAndroid Build Coastguard Workerclass NegotiatingTelnetHandler(socketserver.BaseRequestHandler):
74*6236dae4SAndroid Build Coastguard Worker    """Handler class for Telnet connections."""
75*6236dae4SAndroid Build Coastguard Worker
76*6236dae4SAndroid Build Coastguard Worker    def handle(self):
77*6236dae4SAndroid Build Coastguard Worker        """Negotiates options before reading data."""
78*6236dae4SAndroid Build Coastguard Worker        neg = Negotiator(self.request)
79*6236dae4SAndroid Build Coastguard Worker
80*6236dae4SAndroid Build Coastguard Worker        try:
81*6236dae4SAndroid Build Coastguard Worker            # Send some initial negotiations.
82*6236dae4SAndroid Build Coastguard Worker            neg.send_do("NEW_ENVIRON")
83*6236dae4SAndroid Build Coastguard Worker            neg.send_will("NEW_ENVIRON")
84*6236dae4SAndroid Build Coastguard Worker            neg.send_dont("NAWS")
85*6236dae4SAndroid Build Coastguard Worker            neg.send_wont("NAWS")
86*6236dae4SAndroid Build Coastguard Worker
87*6236dae4SAndroid Build Coastguard Worker            # Get the data passed through the negotiator
88*6236dae4SAndroid Build Coastguard Worker            data = neg.recv(4*1024)
89*6236dae4SAndroid Build Coastguard Worker            log.debug("Incoming data: %r", data)
90*6236dae4SAndroid Build Coastguard Worker
91*6236dae4SAndroid Build Coastguard Worker            if VERIFIED_REQ.encode('utf-8') in data:
92*6236dae4SAndroid Build Coastguard Worker                log.debug("Received verification request from test framework")
93*6236dae4SAndroid Build Coastguard Worker                pid = os.getpid()
94*6236dae4SAndroid Build Coastguard Worker                # see tests/server/util.c function write_pidfile
95*6236dae4SAndroid Build Coastguard Worker                if os.name == "nt":
96*6236dae4SAndroid Build Coastguard Worker                    pid += 65536
97*6236dae4SAndroid Build Coastguard Worker                response = VERIFIED_RSP.format(pid=pid)
98*6236dae4SAndroid Build Coastguard Worker                response_data = response.encode('utf-8')
99*6236dae4SAndroid Build Coastguard Worker            else:
100*6236dae4SAndroid Build Coastguard Worker                log.debug("Received normal request - echoing back")
101*6236dae4SAndroid Build Coastguard Worker                response_data = data.decode('utf-8').strip().encode('utf-8')
102*6236dae4SAndroid Build Coastguard Worker
103*6236dae4SAndroid Build Coastguard Worker            if response_data:
104*6236dae4SAndroid Build Coastguard Worker                log.debug("Sending %r", response_data)
105*6236dae4SAndroid Build Coastguard Worker                self.request.sendall(response_data)
106*6236dae4SAndroid Build Coastguard Worker
107*6236dae4SAndroid Build Coastguard Worker            # put some effort into making a clean socket shutdown
108*6236dae4SAndroid Build Coastguard Worker            # that does not give the client ECONNRESET
109*6236dae4SAndroid Build Coastguard Worker            self.request.settimeout(0.1)
110*6236dae4SAndroid Build Coastguard Worker            self.request.recv(4*1024)
111*6236dae4SAndroid Build Coastguard Worker            self.request.shutdown(socket.SHUT_RDWR)
112*6236dae4SAndroid Build Coastguard Worker
113*6236dae4SAndroid Build Coastguard Worker        except IOError:
114*6236dae4SAndroid Build Coastguard Worker            log.exception("IOError hit during request")
115*6236dae4SAndroid Build Coastguard Worker
116*6236dae4SAndroid Build Coastguard Worker
117*6236dae4SAndroid Build Coastguard Workerclass Negotiator(object):
118*6236dae4SAndroid Build Coastguard Worker    NO_NEG = 0
119*6236dae4SAndroid Build Coastguard Worker    START_NEG = 1
120*6236dae4SAndroid Build Coastguard Worker    WILL = 2
121*6236dae4SAndroid Build Coastguard Worker    WONT = 3
122*6236dae4SAndroid Build Coastguard Worker    DO = 4
123*6236dae4SAndroid Build Coastguard Worker    DONT = 5
124*6236dae4SAndroid Build Coastguard Worker
125*6236dae4SAndroid Build Coastguard Worker    def __init__(self, tcp):
126*6236dae4SAndroid Build Coastguard Worker        self.tcp = tcp
127*6236dae4SAndroid Build Coastguard Worker        self.state = self.NO_NEG
128*6236dae4SAndroid Build Coastguard Worker
129*6236dae4SAndroid Build Coastguard Worker    def recv(self, bytes):
130*6236dae4SAndroid Build Coastguard Worker        """
131*6236dae4SAndroid Build Coastguard Worker        Read bytes from TCP, handling negotiation sequences.
132*6236dae4SAndroid Build Coastguard Worker
133*6236dae4SAndroid Build Coastguard Worker        :param bytes: Number of bytes to read
134*6236dae4SAndroid Build Coastguard Worker        :return: a buffer of bytes
135*6236dae4SAndroid Build Coastguard Worker        """
136*6236dae4SAndroid Build Coastguard Worker        buffer = bytearray()
137*6236dae4SAndroid Build Coastguard Worker
138*6236dae4SAndroid Build Coastguard Worker        # If we keep receiving negotiation sequences, we won't fill the buffer.
139*6236dae4SAndroid Build Coastguard Worker        # Keep looping while we can, and until we have something to give back
140*6236dae4SAndroid Build Coastguard Worker        # to the caller.
141*6236dae4SAndroid Build Coastguard Worker        while len(buffer) == 0:
142*6236dae4SAndroid Build Coastguard Worker            data = self.tcp.recv(bytes)
143*6236dae4SAndroid Build Coastguard Worker            if not data:
144*6236dae4SAndroid Build Coastguard Worker                # TCP failed to give us any data. Break out.
145*6236dae4SAndroid Build Coastguard Worker                break
146*6236dae4SAndroid Build Coastguard Worker
147*6236dae4SAndroid Build Coastguard Worker            for byte_int in bytearray(data):
148*6236dae4SAndroid Build Coastguard Worker                if self.state == self.NO_NEG:
149*6236dae4SAndroid Build Coastguard Worker                    self.no_neg(byte_int, buffer)
150*6236dae4SAndroid Build Coastguard Worker                elif self.state == self.START_NEG:
151*6236dae4SAndroid Build Coastguard Worker                    self.start_neg(byte_int)
152*6236dae4SAndroid Build Coastguard Worker                elif self.state in [self.WILL, self.WONT, self.DO, self.DONT]:
153*6236dae4SAndroid Build Coastguard Worker                    self.handle_option(byte_int)
154*6236dae4SAndroid Build Coastguard Worker                else:
155*6236dae4SAndroid Build Coastguard Worker                    # Received an unexpected byte. Stop negotiations
156*6236dae4SAndroid Build Coastguard Worker                    log.error("Unexpected byte %s in state %s",
157*6236dae4SAndroid Build Coastguard Worker                              byte_int,
158*6236dae4SAndroid Build Coastguard Worker                              self.state)
159*6236dae4SAndroid Build Coastguard Worker                    self.state = self.NO_NEG
160*6236dae4SAndroid Build Coastguard Worker
161*6236dae4SAndroid Build Coastguard Worker        return buffer
162*6236dae4SAndroid Build Coastguard Worker
163*6236dae4SAndroid Build Coastguard Worker    def no_neg(self, byte_int, buffer):
164*6236dae4SAndroid Build Coastguard Worker        # Not negotiating anything thus far. Check to see if we
165*6236dae4SAndroid Build Coastguard Worker        # should.
166*6236dae4SAndroid Build Coastguard Worker        if byte_int == NegTokens.IAC:
167*6236dae4SAndroid Build Coastguard Worker            # Start negotiation
168*6236dae4SAndroid Build Coastguard Worker            log.debug("Starting negotiation (IAC)")
169*6236dae4SAndroid Build Coastguard Worker            self.state = self.START_NEG
170*6236dae4SAndroid Build Coastguard Worker        else:
171*6236dae4SAndroid Build Coastguard Worker            # Just append the incoming byte to the buffer
172*6236dae4SAndroid Build Coastguard Worker            buffer.append(byte_int)
173*6236dae4SAndroid Build Coastguard Worker
174*6236dae4SAndroid Build Coastguard Worker    def start_neg(self, byte_int):
175*6236dae4SAndroid Build Coastguard Worker        # In a negotiation.
176*6236dae4SAndroid Build Coastguard Worker        log.debug("In negotiation (%s)",
177*6236dae4SAndroid Build Coastguard Worker                  NegTokens.from_val(byte_int))
178*6236dae4SAndroid Build Coastguard Worker
179*6236dae4SAndroid Build Coastguard Worker        if byte_int == NegTokens.WILL:
180*6236dae4SAndroid Build Coastguard Worker            # Client is confirming they are willing to do an option
181*6236dae4SAndroid Build Coastguard Worker            log.debug("Client is willing")
182*6236dae4SAndroid Build Coastguard Worker            self.state = self.WILL
183*6236dae4SAndroid Build Coastguard Worker        elif byte_int == NegTokens.WONT:
184*6236dae4SAndroid Build Coastguard Worker            # Client is confirming they are unwilling to do an
185*6236dae4SAndroid Build Coastguard Worker            # option
186*6236dae4SAndroid Build Coastguard Worker            log.debug("Client is unwilling")
187*6236dae4SAndroid Build Coastguard Worker            self.state = self.WONT
188*6236dae4SAndroid Build Coastguard Worker        elif byte_int == NegTokens.DO:
189*6236dae4SAndroid Build Coastguard Worker            # Client is indicating they can do an option
190*6236dae4SAndroid Build Coastguard Worker            log.debug("Client can do")
191*6236dae4SAndroid Build Coastguard Worker            self.state = self.DO
192*6236dae4SAndroid Build Coastguard Worker        elif byte_int == NegTokens.DONT:
193*6236dae4SAndroid Build Coastguard Worker            # Client is indicating they can't do an option
194*6236dae4SAndroid Build Coastguard Worker            log.debug("Client can't do")
195*6236dae4SAndroid Build Coastguard Worker            self.state = self.DONT
196*6236dae4SAndroid Build Coastguard Worker        else:
197*6236dae4SAndroid Build Coastguard Worker            # Received an unexpected byte. Stop negotiations
198*6236dae4SAndroid Build Coastguard Worker            log.error("Unexpected byte %s in state %s",
199*6236dae4SAndroid Build Coastguard Worker                      byte_int,
200*6236dae4SAndroid Build Coastguard Worker                      self.state)
201*6236dae4SAndroid Build Coastguard Worker            self.state = self.NO_NEG
202*6236dae4SAndroid Build Coastguard Worker
203*6236dae4SAndroid Build Coastguard Worker    def handle_option(self, byte_int):
204*6236dae4SAndroid Build Coastguard Worker        if byte_int in [NegOptions.BINARY,
205*6236dae4SAndroid Build Coastguard Worker                        NegOptions.CHARSET,
206*6236dae4SAndroid Build Coastguard Worker                        NegOptions.SUPPRESS_GO_AHEAD,
207*6236dae4SAndroid Build Coastguard Worker                        NegOptions.NAWS,
208*6236dae4SAndroid Build Coastguard Worker                        NegOptions.NEW_ENVIRON]:
209*6236dae4SAndroid Build Coastguard Worker            log.debug("Option: %s", NegOptions.from_val(byte_int))
210*6236dae4SAndroid Build Coastguard Worker
211*6236dae4SAndroid Build Coastguard Worker            # No further negotiation of this option needed. Reset the state.
212*6236dae4SAndroid Build Coastguard Worker            self.state = self.NO_NEG
213*6236dae4SAndroid Build Coastguard Worker
214*6236dae4SAndroid Build Coastguard Worker        else:
215*6236dae4SAndroid Build Coastguard Worker            # Received an unexpected byte. Stop negotiations
216*6236dae4SAndroid Build Coastguard Worker            log.error("Unexpected byte %s in state %s",
217*6236dae4SAndroid Build Coastguard Worker                      byte_int,
218*6236dae4SAndroid Build Coastguard Worker                      self.state)
219*6236dae4SAndroid Build Coastguard Worker            self.state = self.NO_NEG
220*6236dae4SAndroid Build Coastguard Worker
221*6236dae4SAndroid Build Coastguard Worker    def send_message(self, message_ints):
222*6236dae4SAndroid Build Coastguard Worker        self.tcp.sendall(bytearray(message_ints))
223*6236dae4SAndroid Build Coastguard Worker
224*6236dae4SAndroid Build Coastguard Worker    def send_iac(self, arr):
225*6236dae4SAndroid Build Coastguard Worker        message = [NegTokens.IAC]
226*6236dae4SAndroid Build Coastguard Worker        message.extend(arr)
227*6236dae4SAndroid Build Coastguard Worker        self.send_message(message)
228*6236dae4SAndroid Build Coastguard Worker
229*6236dae4SAndroid Build Coastguard Worker    def send_do(self, option_str):
230*6236dae4SAndroid Build Coastguard Worker        log.debug("Sending DO %s", option_str)
231*6236dae4SAndroid Build Coastguard Worker        self.send_iac([NegTokens.DO, NegOptions.to_val(option_str)])
232*6236dae4SAndroid Build Coastguard Worker
233*6236dae4SAndroid Build Coastguard Worker    def send_dont(self, option_str):
234*6236dae4SAndroid Build Coastguard Worker        log.debug("Sending DONT %s", option_str)
235*6236dae4SAndroid Build Coastguard Worker        self.send_iac([NegTokens.DONT, NegOptions.to_val(option_str)])
236*6236dae4SAndroid Build Coastguard Worker
237*6236dae4SAndroid Build Coastguard Worker    def send_will(self, option_str):
238*6236dae4SAndroid Build Coastguard Worker        log.debug("Sending WILL %s", option_str)
239*6236dae4SAndroid Build Coastguard Worker        self.send_iac([NegTokens.WILL, NegOptions.to_val(option_str)])
240*6236dae4SAndroid Build Coastguard Worker
241*6236dae4SAndroid Build Coastguard Worker    def send_wont(self, option_str):
242*6236dae4SAndroid Build Coastguard Worker        log.debug("Sending WONT %s", option_str)
243*6236dae4SAndroid Build Coastguard Worker        self.send_iac([NegTokens.WONT, NegOptions.to_val(option_str)])
244*6236dae4SAndroid Build Coastguard Worker
245*6236dae4SAndroid Build Coastguard Worker
246*6236dae4SAndroid Build Coastguard Workerclass NegBase(object):
247*6236dae4SAndroid Build Coastguard Worker    @classmethod
248*6236dae4SAndroid Build Coastguard Worker    def to_val(cls, name):
249*6236dae4SAndroid Build Coastguard Worker        return getattr(cls, name)
250*6236dae4SAndroid Build Coastguard Worker
251*6236dae4SAndroid Build Coastguard Worker    @classmethod
252*6236dae4SAndroid Build Coastguard Worker    def from_val(cls, val):
253*6236dae4SAndroid Build Coastguard Worker        for k in cls.__dict__:
254*6236dae4SAndroid Build Coastguard Worker            if getattr(cls, k) == val:
255*6236dae4SAndroid Build Coastguard Worker                return k
256*6236dae4SAndroid Build Coastguard Worker
257*6236dae4SAndroid Build Coastguard Worker        return "<unknown>"
258*6236dae4SAndroid Build Coastguard Worker
259*6236dae4SAndroid Build Coastguard Worker
260*6236dae4SAndroid Build Coastguard Workerclass NegTokens(NegBase):
261*6236dae4SAndroid Build Coastguard Worker    # The start of a negotiation sequence
262*6236dae4SAndroid Build Coastguard Worker    IAC = 255
263*6236dae4SAndroid Build Coastguard Worker    # Confirm willingness to negotiate
264*6236dae4SAndroid Build Coastguard Worker    WILL = 251
265*6236dae4SAndroid Build Coastguard Worker    # Confirm unwillingness to negotiate
266*6236dae4SAndroid Build Coastguard Worker    WONT = 252
267*6236dae4SAndroid Build Coastguard Worker    # Indicate willingness to negotiate
268*6236dae4SAndroid Build Coastguard Worker    DO = 253
269*6236dae4SAndroid Build Coastguard Worker    # Indicate unwillingness to negotiate
270*6236dae4SAndroid Build Coastguard Worker    DONT = 254
271*6236dae4SAndroid Build Coastguard Worker
272*6236dae4SAndroid Build Coastguard Worker    # The start of sub-negotiation options.
273*6236dae4SAndroid Build Coastguard Worker    SB = 250
274*6236dae4SAndroid Build Coastguard Worker    # The end of sub-negotiation options.
275*6236dae4SAndroid Build Coastguard Worker    SE = 240
276*6236dae4SAndroid Build Coastguard Worker
277*6236dae4SAndroid Build Coastguard Worker
278*6236dae4SAndroid Build Coastguard Workerclass NegOptions(NegBase):
279*6236dae4SAndroid Build Coastguard Worker    # Binary Transmission
280*6236dae4SAndroid Build Coastguard Worker    BINARY = 0
281*6236dae4SAndroid Build Coastguard Worker    # Suppress Go Ahead
282*6236dae4SAndroid Build Coastguard Worker    SUPPRESS_GO_AHEAD = 3
283*6236dae4SAndroid Build Coastguard Worker    # NAWS - width and height of client
284*6236dae4SAndroid Build Coastguard Worker    NAWS = 31
285*6236dae4SAndroid Build Coastguard Worker    # NEW-ENVIRON - environment variables on client
286*6236dae4SAndroid Build Coastguard Worker    NEW_ENVIRON = 39
287*6236dae4SAndroid Build Coastguard Worker    # Charset option
288*6236dae4SAndroid Build Coastguard Worker    CHARSET = 42
289*6236dae4SAndroid Build Coastguard Worker
290*6236dae4SAndroid Build Coastguard Worker
291*6236dae4SAndroid Build Coastguard Workerdef get_options():
292*6236dae4SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
293*6236dae4SAndroid Build Coastguard Worker
294*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--port", action="store", default=9019,
295*6236dae4SAndroid Build Coastguard Worker                        type=int, help="port to listen on")
296*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--verbose", action="store", type=int, default=0,
297*6236dae4SAndroid Build Coastguard Worker                        help="verbose output")
298*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--pidfile", action="store",
299*6236dae4SAndroid Build Coastguard Worker                        help="file name for the PID")
300*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--logfile", action="store",
301*6236dae4SAndroid Build Coastguard Worker                        help="file name for the log")
302*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--srcdir", action="store", help="test directory")
303*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--id", action="store", help="server ID")
304*6236dae4SAndroid Build Coastguard Worker    parser.add_argument("--ipv4", action="store_true", default=0,
305*6236dae4SAndroid Build Coastguard Worker                        help="IPv4 flag")
306*6236dae4SAndroid Build Coastguard Worker
307*6236dae4SAndroid Build Coastguard Worker    return parser.parse_args()
308*6236dae4SAndroid Build Coastguard Worker
309*6236dae4SAndroid Build Coastguard Worker
310*6236dae4SAndroid Build Coastguard Workerdef setup_logging(options):
311*6236dae4SAndroid Build Coastguard Worker    """Set up logging from the command line options."""
312*6236dae4SAndroid Build Coastguard Worker    root_logger = logging.getLogger()
313*6236dae4SAndroid Build Coastguard Worker    add_stdout = False
314*6236dae4SAndroid Build Coastguard Worker
315*6236dae4SAndroid Build Coastguard Worker    formatter = logging.Formatter("%(asctime)s %(levelname)-5.5s "
316*6236dae4SAndroid Build Coastguard Worker                                  "[{ident}] %(message)s"
317*6236dae4SAndroid Build Coastguard Worker                                  .format(ident=IDENT))
318*6236dae4SAndroid Build Coastguard Worker
319*6236dae4SAndroid Build Coastguard Worker    # Write out to a logfile
320*6236dae4SAndroid Build Coastguard Worker    if options.logfile:
321*6236dae4SAndroid Build Coastguard Worker        handler = ClosingFileHandler(options.logfile)
322*6236dae4SAndroid Build Coastguard Worker        handler.setFormatter(formatter)
323*6236dae4SAndroid Build Coastguard Worker        handler.setLevel(logging.DEBUG)
324*6236dae4SAndroid Build Coastguard Worker        root_logger.addHandler(handler)
325*6236dae4SAndroid Build Coastguard Worker    else:
326*6236dae4SAndroid Build Coastguard Worker        # The logfile wasn't specified. Add a stdout logger.
327*6236dae4SAndroid Build Coastguard Worker        add_stdout = True
328*6236dae4SAndroid Build Coastguard Worker
329*6236dae4SAndroid Build Coastguard Worker    if options.verbose:
330*6236dae4SAndroid Build Coastguard Worker        # Add a stdout logger as well in verbose mode
331*6236dae4SAndroid Build Coastguard Worker        root_logger.setLevel(logging.DEBUG)
332*6236dae4SAndroid Build Coastguard Worker        add_stdout = True
333*6236dae4SAndroid Build Coastguard Worker    else:
334*6236dae4SAndroid Build Coastguard Worker        root_logger.setLevel(logging.INFO)
335*6236dae4SAndroid Build Coastguard Worker
336*6236dae4SAndroid Build Coastguard Worker    if add_stdout:
337*6236dae4SAndroid Build Coastguard Worker        stdout_handler = logging.StreamHandler(sys.stdout)
338*6236dae4SAndroid Build Coastguard Worker        stdout_handler.setFormatter(formatter)
339*6236dae4SAndroid Build Coastguard Worker        stdout_handler.setLevel(logging.DEBUG)
340*6236dae4SAndroid Build Coastguard Worker        root_logger.addHandler(stdout_handler)
341*6236dae4SAndroid Build Coastguard Worker
342*6236dae4SAndroid Build Coastguard Worker
343*6236dae4SAndroid Build Coastguard Workerclass ScriptRC(object):
344*6236dae4SAndroid Build Coastguard Worker    """Enum for script return codes."""
345*6236dae4SAndroid Build Coastguard Worker
346*6236dae4SAndroid Build Coastguard Worker    SUCCESS = 0
347*6236dae4SAndroid Build Coastguard Worker    FAILURE = 1
348*6236dae4SAndroid Build Coastguard Worker    EXCEPTION = 2
349*6236dae4SAndroid Build Coastguard Worker
350*6236dae4SAndroid Build Coastguard Worker
351*6236dae4SAndroid Build Coastguard Workerif __name__ == '__main__':
352*6236dae4SAndroid Build Coastguard Worker    # Get the options from the user.
353*6236dae4SAndroid Build Coastguard Worker    options = get_options()
354*6236dae4SAndroid Build Coastguard Worker
355*6236dae4SAndroid Build Coastguard Worker    # Setup logging using the user options
356*6236dae4SAndroid Build Coastguard Worker    setup_logging(options)
357*6236dae4SAndroid Build Coastguard Worker
358*6236dae4SAndroid Build Coastguard Worker    # Run main script.
359*6236dae4SAndroid Build Coastguard Worker    try:
360*6236dae4SAndroid Build Coastguard Worker        rc = telnetserver(options)
361*6236dae4SAndroid Build Coastguard Worker    except Exception:
362*6236dae4SAndroid Build Coastguard Worker        log.exception('Error in telnet server')
363*6236dae4SAndroid Build Coastguard Worker        rc = ScriptRC.EXCEPTION
364*6236dae4SAndroid Build Coastguard Worker
365*6236dae4SAndroid Build Coastguard Worker    if options.pidfile and os.path.isfile(options.pidfile):
366*6236dae4SAndroid Build Coastguard Worker        os.unlink(options.pidfile)
367*6236dae4SAndroid Build Coastguard Worker
368*6236dae4SAndroid Build Coastguard Worker    log.info("Returning %d", rc)
369*6236dae4SAndroid Build Coastguard Worker    sys.exit(rc)
370