'Create a new hidden service. If the directory is already present, a
new port is added. This provides a **namedtuple** of the following...
* path (str) - hidden service directory
* hostname (str) - Content of the hostname file, if no **client_names**
are provided this is the onion address of the service. This is only
retrieved if we can read the hidden service directory.
* hostname_for_client (dict) - mapping of client names to their onion
address, this is only set if the **client_names** was provided and we
can read the hidden service directory
* config (dict) - tor\'s new hidden service configuration
Our *.onion address is fetched by reading the hidden service directory.
However, this directory is only readable by the tor user, so if unavailable
the **hostname** will be **None**.
**As of Tor 0.2.7.1 there\'s two ways for creating hidden services. This is
no longer the recommended method.** Rather, try using
:func:`~stem.control.Controller.create_ephemeral_hidden_service` instead.
.. versionadded:: 1.3.0
.. versionchanged:: 1.4.0
Added the auth_type and client_names arguments.
:param str path: path for the hidden service\'s data directory
:param int port: hidden service port
:param str target_address: address of the service, by default 127.0.0.1
:param int target_port: port of the service, by default this is the same as
**port**
:param str auth_type: authentication type: basic, stealth or None to disable auth
:param list client_names: client names (1-16 characters "A-Za-z0-9+-_")
:returns: **CreateHiddenServiceOutput** if we create or update a hidden service, **None** otherwise
:raises: :class:`stem.ControllerError` if the call fails'

def create_hidden_service(self, path, port, target_address=None, target_port=None, auth_type=None, client_names=None):

    if (not stem.util.connection.is_valid_port(port)):
        raise ValueError(("%s    isn't    a    valid    port    number" % port))
    elif (target_address and (not stem.util.connection.is_valid_ipv4_address(target_address))):
        raise ValueError(("%s    isn't    a    valid    IPv4    address" % target_address))
    elif ((target_port is not None) and (not stem.util.connection.is_valid_port(target_port))):
        raise ValueError(("%s    isn't    a    valid    port    number" % target_port))
    elif (auth_type not in (None, 'basic', 'stealth')):
        raise ValueError(("%s    isn't    a    recognized    type    of    authentication" % auth_type))
    port = int(port)
    target_address = (target_address if target_address else '127.0.0.1')
    target_port = (port if (target_port is None) else int(target_port))
    conf = self.get_hidden_service_conf()
    if ((path in conf) and ((port, target_address, target_port) in conf[path]['HiddenServicePort'])):
        return None
    conf.setdefault(path, OrderedDict()).setdefault('HiddenServicePort', []).append((port, target_address, target_port))
    if (auth_type and client_names):
        hsac = ('%s    %s' % (auth_type, ','.join(client_names)))
        conf[path]['HiddenServiceAuthorizeClient'] = hsac
    self.set_hidden_service_conf(conf)
    (hostname, hostname_for_client) = (None, {})
    if self.is_localhost():
        hostname_path = os.path.join(path, 'hostname')
        if (not os.path.isabs(hostname_path)):
            cwd = stem.util.system.cwd(self.get_pid(None))
            if cwd:
                hostname_path = stem.util.system.expand_path(hostname_path, cwd)
        if os.path.isabs(hostname_path):
            start_time = time.time()
            while (not os.path.exists(hostname_path)):
                wait_time = (time.time() - start_time)
                if (wait_time >= 3):
                    break
                else:
                    time.sleep(0.05)
            try:
                with open(hostname_path) as hostname_file:
                    hostname = hostname_file.read().strip()
                    if (client_names and ('\n' in hostname)):
                        for line in hostname.splitlines():
                            if ('    #    client:    ' in line):
                                address = line.split()[0]
                                client = line.split('    #    client:    ', 1)[1]
                                if ((len(address) == 22) and address.endswith('.onion')):
                                    hostname_for_client[client] = address
            except:
                pass
    return CreateHiddenServiceOutput(path=path, hostname=hostname, hostname_for_client=hostname_for_client, config=conf)
