Linux specific helper function.
    Returns set of ip host addresses of remote established connections
    on local tcp port port.

    Parses output of shell 'lsof'
    to get connections

    $ sudo lsof -iTCP:4505 -n
    COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
    Python   9971 root   35u  IPv4 0x18a8464a29ca329d      0t0  TCP *:4505 (LISTEN)
    Python   9971 root   37u  IPv4 0x18a8464a29b2b29d      0t0  TCP 127.0.0.1:4505->127.0.0.1:55703 (ESTABLISHED)
    Python  10152 root   22u  IPv4 0x18a8464a29c8cab5      0t0  TCP 127.0.0.1:55703->127.0.0.1:4505 (ESTABLISHED)
    Python  10153 root   22u  IPv4 0x18a8464a29c8cab5      0t0  TCP [fe80::249a]:4505->[fe80::150]:59367 (ESTABLISHED)

def _linux_remotes_on(port, which_end):
    '''
    Linux specific helper function.
    Returns set of ip host addresses of remote established connections
    on local tcp port port.

    Parses output of shell 'lsof'
    to get connections

    $ sudo lsof -iTCP:4505 -n
    COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
    Python   9971 root   35u  IPv4 0x18a8464a29ca329d      0t0  TCP *:4505 (LISTEN)
    Python   9971 root   37u  IPv4 0x18a8464a29b2b29d      0t0  TCP 127.0.0.1:4505->127.0.0.1:55703 (ESTABLISHED)
    Python  10152 root   22u  IPv4 0x18a8464a29c8cab5      0t0  TCP 127.0.0.1:55703->127.0.0.1:4505 (ESTABLISHED)
    Python  10153 root   22u  IPv4 0x18a8464a29c8cab5      0t0  TCP [fe80::249a]:4505->[fe80::150]:59367 (ESTABLISHED)

    '''
    remotes = set()

    try:
        data = subprocess.check_output(
            ['lsof', '-iTCP:{0:d}'.format(port), '-n', '-P']  # pylint: disable=minimum-python-version
        )
    except subprocess.CalledProcessError as ex:
        if ex.returncode == 1:
            # Lsof return 1 if any error was detected, including the failure
            # to locate Internet addresses, and it is not an error in this case.
            log.warning('"lsof" returncode = 1, likely no active TCP sessions.')
            return remotes
        log.error('Failed "lsof" with returncode = %s', ex.returncode)
        raise

    lines = salt.utils.stringutils.to_str(data).split('\n')
    for line in lines:
        chunks = line.split()
        if not chunks:
            continue
        # ['Python', '9971', 'root', '37u', 'IPv4', '0x18a8464a29b2b29d', '0t0',
        # 'TCP', '127.0.0.1:4505->127.0.0.1:55703', '(ESTABLISHED)']
        # print chunks
        if 'COMMAND' in chunks[0]:
            continue  # ignore header
        if 'ESTABLISHED' not in chunks[-1]:
            continue  # ignore if not ESTABLISHED
        # '127.0.0.1:4505->127.0.0.1:55703'
        local, remote = chunks[8].split('->')
        _, lport = local.rsplit(':', 1)
        rhost, rport = remote.rsplit(':', 1)
        if which_end == 'remote_port' and int(rport) != port:
            continue
        if which_end == 'local_port' and int(lport) != port:
            continue
        remotes.add(rhost.strip("[]"))

    return remotes