14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# A higher level module for using sockets (or Windows named pipes)
34adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# multiprocessing/connection.py
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Copyright (c) 2006-2008, R Oudkerk
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# All rights reserved.
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Redistribution and use in source and binary forms, with or without
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# modification, are permitted provided that the following conditions
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# are met:
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# 1. Redistributions of source code must retain the above copyright
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#    notice, this list of conditions and the following disclaimer.
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# 2. Redistributions in binary form must reproduce the above copyright
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#    notice, this list of conditions and the following disclaimer in the
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#    documentation and/or other materials provided with the distribution.
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# 3. Neither the name of author nor the names of any contributors may be
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#    used to endorse or promote products derived from this software
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#    without specific prior written permission.
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# SUCH DAMAGE.
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao__all__ = [ 'Client', 'Listener', 'Pipe' ]
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport os
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport sys
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport socket
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport errno
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport time
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport tempfile
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport itertools
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport _multiprocessing
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom multiprocessing import current_process, AuthenticationError
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom multiprocessing.util import get_temp_dir, Finalize, sub_debug, debug
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom multiprocessing.forking import duplicate, close
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
554adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoBUFSIZE = 8192
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# A very generous timeout when it comes to local connections...
574adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoCONNECTION_TIMEOUT = 20.
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao_mmap_counter = itertools.count()
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodefault_family = 'AF_INET'
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofamilies = ['AF_INET']
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif hasattr(socket, 'AF_UNIX'):
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    default_family = 'AF_UNIX'
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    families += ['AF_UNIX']
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif sys.platform == 'win32':
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    default_family = 'AF_PIPE'
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    families += ['AF_PIPE']
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _init_timeout(timeout=CONNECTION_TIMEOUT):
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return time.time() + timeout
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _check_timeout(t):
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return time.time() > t
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef arbitrary_address(family):
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Return an arbitrary free address for the given family
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if family == 'AF_INET':
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return ('localhost', 0)
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif family == 'AF_UNIX':
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return tempfile.mktemp(prefix='listener-', dir=get_temp_dir())
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif family == 'AF_PIPE':
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' %
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                               (os.getpid(), _mmap_counter.next()))
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise ValueError('unrecognized family')
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef address_type(address):
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Return the types of the address
1014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    This can be 'AF_INET', 'AF_UNIX', or 'AF_PIPE'
1034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
1044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if type(address) == tuple:
1054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 'AF_INET'
1064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif type(address) is str and address.startswith('\\\\'):
1074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 'AF_PIPE'
1084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif type(address) is str:
1094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 'AF_UNIX'
1104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
1114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise ValueError('address type of %r unrecognized' % address)
1124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
1144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Public functions
1154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
1164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass Listener(object):
1184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
1194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Returns a listener object.
1204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    This is a wrapper for a bound socket which is 'listening' for
1224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    connections, or for a Windows named pipe.
1234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
1244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, address=None, family=None, backlog=1, authkey=None):
1254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        family = family or (address and address_type(address)) \
1264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                 or default_family
1274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        address = address or arbitrary_address(family)
1284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if family == 'AF_PIPE':
1304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._listener = PipeListener(address, backlog)
1314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._listener = SocketListener(address, family, backlog)
1334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if authkey is not None and not isinstance(authkey, bytes):
1354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise TypeError, 'authkey should be a byte string'
1364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._authkey = authkey
1384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def accept(self):
1404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
1414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Accept a connection on the bound socket or named pipe of `self`.
1424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Returns a `Connection` object.
1444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
1454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        c = self._listener.accept()
1464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if self._authkey:
1474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            deliver_challenge(c, self._authkey)
1484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            answer_challenge(c, self._authkey)
1494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return c
1504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def close(self):
1524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
1534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Close the bound socket or named pipe of `self`.
1544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
1554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._listener.close()
1564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    address = property(lambda self: self._listener._address)
1584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    last_accepted = property(lambda self: self._listener._last_accepted)
1594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef Client(address, family=None, authkey=None):
1624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
1634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Returns a connection to the address of a `Listener`
1644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
1654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    family = family or address_type(address)
1664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if family == 'AF_PIPE':
1674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        c = PipeClient(address)
1684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
1694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        c = SocketClient(address)
1704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if authkey is not None and not isinstance(authkey, bytes):
1724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise TypeError, 'authkey should be a byte string'
1734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if authkey is not None:
1754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        answer_challenge(c, authkey)
1764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        deliver_challenge(c, authkey)
1774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return c
1794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif sys.platform != 'win32':
1824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def Pipe(duplex=True):
1844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
1854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Returns pair of connection objects at either end of a pipe
1864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
1874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if duplex:
1884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s1, s2 = socket.socketpair()
1894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s1.setblocking(True)
1904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s2.setblocking(True)
1914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            c1 = _multiprocessing.Connection(os.dup(s1.fileno()))
1924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            c2 = _multiprocessing.Connection(os.dup(s2.fileno()))
1934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s1.close()
1944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s2.close()
1954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            fd1, fd2 = os.pipe()
1974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            c1 = _multiprocessing.Connection(fd1, writable=False)
1984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            c2 = _multiprocessing.Connection(fd2, readable=False)
1994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return c1, c2
2014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoelse:
2034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    from _multiprocessing import win32
2044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def Pipe(duplex=True):
2064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
2074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Returns pair of connection objects at either end of a pipe
2084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
2094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        address = arbitrary_address('AF_PIPE')
2104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if duplex:
2114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            openmode = win32.PIPE_ACCESS_DUPLEX
2124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            access = win32.GENERIC_READ | win32.GENERIC_WRITE
2134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            obsize, ibsize = BUFSIZE, BUFSIZE
2144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
2154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            openmode = win32.PIPE_ACCESS_INBOUND
2164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            access = win32.GENERIC_WRITE
2174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            obsize, ibsize = 0, BUFSIZE
2184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        h1 = win32.CreateNamedPipe(
2204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            address, openmode,
2214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE |
2224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            win32.PIPE_WAIT,
2234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            1, obsize, ibsize, win32.NMPWAIT_WAIT_FOREVER, win32.NULL
2244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            )
2254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        h2 = win32.CreateFile(
2264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            address, access, 0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL
2274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            )
2284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        win32.SetNamedPipeHandleState(
2294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            h2, win32.PIPE_READMODE_MESSAGE, None, None
2304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            )
2314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
2334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            win32.ConnectNamedPipe(h1, win32.NULL)
2344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except WindowsError, e:
2354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if e.args[0] != win32.ERROR_PIPE_CONNECTED:
2364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                raise
2374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        c1 = _multiprocessing.PipeConnection(h1, writable=duplex)
2394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        c2 = _multiprocessing.PipeConnection(h2, readable=duplex)
2404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return c1, c2
2424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
2444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Definitions for connections based on sockets
2454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
2464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass SocketListener(object):
2484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
2494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Representation of a socket which is bound to an address and listening
2504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
2514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, address, family, backlog=1):
2524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._socket = socket.socket(getattr(socket, family))
2534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
2544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
2554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._socket.setblocking(True)
2564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._socket.bind(address)
2574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._socket.listen(backlog)
2584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._address = self._socket.getsockname()
2594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except socket.error:
2604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._socket.close()
2614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise
2624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._family = family
2634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._last_accepted = None
2644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if family == 'AF_UNIX':
2664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._unlink = Finalize(
2674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                self, os.unlink, args=(address,), exitpriority=0
2684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                )
2694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
2704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._unlink = None
2714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def accept(self):
2734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        s, self._last_accepted = self._socket.accept()
2744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        s.setblocking(True)
2754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        fd = duplicate(s.fileno())
2764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        conn = _multiprocessing.Connection(fd)
2774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        s.close()
2784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return conn
2794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def close(self):
2814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._socket.close()
2824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if self._unlink is not None:
2834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._unlink()
2844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef SocketClient(address):
2874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
2884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Return a connection object connected to the socket given by `address`
2894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '''
2904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    family = address_type(address)
2914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    s = socket.socket( getattr(socket, family) )
2924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    s.setblocking(True)
2934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    t = _init_timeout()
2944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    while 1:
2964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
2974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s.connect(address)
2984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except socket.error, e:
2994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if e.args[0] != errno.ECONNREFUSED or _check_timeout(t):
3004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                debug('failed to connect to address %s', address)
3014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                raise
3024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            time.sleep(0.01)
3034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
3044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            break
3054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
3064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise
3074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    fd = duplicate(s.fileno())
3094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    conn = _multiprocessing.Connection(fd)
3104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    s.close()
3114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return conn
3124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
3144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Definitions for connections based on named pipes
3154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
3164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif sys.platform == 'win32':
3184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    class PipeListener(object):
3204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
3214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Representation of a named pipe
3224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
3234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __init__(self, address, backlog=None):
3244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._address = address
3254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            handle = win32.CreateNamedPipe(
3264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                address, win32.PIPE_ACCESS_DUPLEX,
3274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE |
3284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.PIPE_WAIT,
3294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE,
3304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.NMPWAIT_WAIT_FOREVER, win32.NULL
3314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                )
3324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._handle_queue = [handle]
3334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._last_accepted = None
3344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            sub_debug('listener created with address=%r', self._address)
3364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.close = Finalize(
3384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                self, PipeListener._finalize_pipe_listener,
3394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                args=(self._handle_queue, self._address), exitpriority=0
3404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                )
3414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def accept(self):
3434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            newhandle = win32.CreateNamedPipe(
3444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                self._address, win32.PIPE_ACCESS_DUPLEX,
3454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE |
3464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.PIPE_WAIT,
3474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE,
3484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.NMPWAIT_WAIT_FOREVER, win32.NULL
3494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                )
3504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self._handle_queue.append(newhandle)
3514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            handle = self._handle_queue.pop(0)
3524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            try:
3534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.ConnectNamedPipe(handle, win32.NULL)
3544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            except WindowsError, e:
3554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # ERROR_NO_DATA can occur if a client has already connected,
3564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # written data and then disconnected -- see Issue 14725.
3574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if e.args[0] not in (win32.ERROR_PIPE_CONNECTED,
3584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                     win32.ERROR_NO_DATA):
3594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    raise
3604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return _multiprocessing.PipeConnection(handle)
3614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        @staticmethod
3634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def _finalize_pipe_listener(queue, address):
3644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            sub_debug('closing listener with address=%r', address)
3654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            for handle in queue:
3664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                close(handle)
3674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def PipeClient(address):
3694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
3704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Return a connection object connected to the pipe given by `address`
3714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '''
3724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        t = _init_timeout()
3734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        while 1:
3744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            try:
3754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                win32.WaitNamedPipe(address, 1000)
3764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                h = win32.CreateFile(
3774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    address, win32.GENERIC_READ | win32.GENERIC_WRITE,
3784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL
3794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    )
3804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            except WindowsError, e:
3814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if e.args[0] not in (win32.ERROR_SEM_TIMEOUT,
3824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                     win32.ERROR_PIPE_BUSY) or _check_timeout(t):
3834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    raise
3844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            else:
3854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                break
3864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
3874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise
3884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        win32.SetNamedPipeHandleState(
3904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            h, win32.PIPE_READMODE_MESSAGE, None, None
3914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            )
3924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return _multiprocessing.PipeConnection(h)
3934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
3954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Authentication stuff
3964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
3974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3984adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoMESSAGE_LENGTH = 20
3994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4004adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoCHALLENGE = b'#CHALLENGE#'
4014adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoWELCOME = b'#WELCOME#'
4024adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoFAILURE = b'#FAILURE#'
4034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef deliver_challenge(connection, authkey):
4054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    import hmac
4064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    assert isinstance(authkey, bytes)
4074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    message = os.urandom(MESSAGE_LENGTH)
4084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    connection.send_bytes(CHALLENGE + message)
4094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    digest = hmac.new(authkey, message).digest()
4104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    response = connection.recv_bytes(256)        # reject large message
4114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if response == digest:
4124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        connection.send_bytes(WELCOME)
4134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
4144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        connection.send_bytes(FAILURE)
4154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise AuthenticationError('digest received was wrong')
4164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef answer_challenge(connection, authkey):
4184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    import hmac
4194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    assert isinstance(authkey, bytes)
4204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    message = connection.recv_bytes(256)         # reject large message
4214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message
4224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    message = message[len(CHALLENGE):]
4234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    digest = hmac.new(authkey, message).digest()
4244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    connection.send_bytes(digest)
4254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    response = connection.recv_bytes(256)        # reject large message
4264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if response != WELCOME:
4274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise AuthenticationError('digest sent was rejected')
4284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
4304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Support for using xmlrpclib for serialization
4314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
4324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass ConnectionWrapper(object):
4344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, dumps, loads):
4354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._conn = conn
4364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._dumps = dumps
4374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._loads = loads
4384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for attr in ('fileno', 'close', 'poll', 'recv_bytes', 'send_bytes'):
4394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            obj = getattr(conn, attr)
4404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            setattr(self, attr, obj)
4414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def send(self, obj):
4424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        s = self._dumps(obj)
4434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._conn.send_bytes(s)
4444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def recv(self):
4454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        s = self._conn.recv_bytes()
4464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._loads(s)
4474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _xml_dumps(obj):
4494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return xmlrpclib.dumps((obj,), None, None, None, 1).encode('utf8')
4504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _xml_loads(s):
4524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    (obj,), method = xmlrpclib.loads(s.decode('utf8'))
4534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return obj
4544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass XmlListener(Listener):
4564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def accept(self):
4574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        global xmlrpclib
4584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        import xmlrpclib
4594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        obj = Listener.accept(self)
4604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return ConnectionWrapper(obj, _xml_dumps, _xml_loads)
4614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef XmlClient(*args, **kwds):
4634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    global xmlrpclib
4644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    import xmlrpclib
4654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return ConnectionWrapper(Client(*args, **kwds), _xml_dumps, _xml_loads)
466