########################################################################
#
#  Copyright (C) 2009, CZ.NIC, z.s.p.o.
# 
#  This file is part of dnstester.
#
#  dnstester is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  dnstester is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
########################################################################

from ctypes import *

BUFFER_SIZE = 16000
AF_UNSPEC = 0


class IpAdapterAddressesHeader(Structure):
    _fields_ = [
        ('Length', c_ulong),
        ('IfIndex', c_uint),
    ]


class IpAdapterAddressesHeaderUnion(Union):
    _fields_ = [
        ('h', IpAdapterAddressesHeader),
        ('Alignment', c_ulonglong),
    ]


class InAddr(Structure):
    _fields_ = [
        ('bytes', c_ubyte * 4)
    ]

class SockAddrIPv4(Structure):
    _fields_ = [
        ('sin_port', c_ushort),
        ('sin_addr', InAddr),
        ('zero', c_ubyte * 8),
    ]


class SockAddrUnion(Union):
    _fields_ = [
        ('ipv4', SockAddrIPv4),
    ]


class SockAddr(Structure):
    _fields_ = [
        ('sa_family', c_short),
        ('subtype', SockAddrUnion),
    ]


class SocketAddress(Structure):
    _fields_ = [
        ('lpSockAddr', POINTER(SockAddr)),
        ('iSockaddrLength', c_int),
    ]

class IpAdapterUnicastAddress(Structure):
    pass

IpAdapterUnicastAddress._fields_ = [
    ('Length', c_ulong),
    ('Flags', c_uint),
    ('Next', POINTER(IpAdapterUnicastAddress)),
    ('Address', SocketAddress),
]
    

class IpAdapterAddresses(Structure):
    pass

IpAdapterAddresses._fields_ = [
    ('h', IpAdapterAddressesHeaderUnion),
    ('Next', POINTER(IpAdapterAddresses)),
    ('AdapterName', c_char_p),
    ('FirstUnicastAddress', POINTER(IpAdapterUnicastAddress)),
]


def get_addresses(adapter):
    r = []
    addr = adapter.FirstUnicastAddress
    while addr:
        sock_addr = addr.contents.Address.lpSockAddr.contents
        if sock_addr.sa_family == 2:
            b = []
            for i in range(4): b.append(sock_addr.subtype.ipv4.sin_addr.bytes[i])
            r.append("%d.%d.%d.%d" % tuple(b))
        else:
            print "unknown sa_family %d\n" % sock_add.sa_family
        addr = addr.contents.Next
    return r
    

def host_addresses():

    try:
        get_ip_net_table = windll.iphlpapi.GetAdaptersAddresses

        buffer = (c_ubyte * BUFFER_SIZE)()
        size = c_uint(BUFFER_SIZE)

        r = get_ip_net_table(
            c_ulong(AF_UNSPEC),
            c_ulong(0),
            c_void_p(None),
            byref(buffer),
            byref(size)
            )

        if r != 0:
            return None, ("invalid GetAdapterAddresses result (code %d)" % r)

        adapter = cast(buffer, POINTER(IpAdapterAddresses))

        addresses = []

        while adapter.contents.Next:
            addresses.extend(get_addresses(adapter.contents))
            adapter = adapter.contents.Next

        return addresses, ''
    except:
        return None, 'exception in host_addresses() routine'

