(module windows mzscheme
(require (lib "foreign.ss"))
(unsafe!)
(define ERROR_BUFFER_OVERFLOW 111)
(define NO_ERROR 0)
(define (bytes->string/zero-terminated bytes)
(let loop ([i 0])
(if (or (>= i (bytes-length bytes))
(zero? (bytes-ref bytes i)))
(bytes->string/latin-1 bytes #f 0 i)
(loop (add1 i)))))
(define sizeof-IP_ADAPTER_INFO 648)
(define (adapter-info p)
(let ([raw (make-sized-byte-string p sizeof-IP_ADAPTER_INFO)])
(let ([AdapterName (bytes->string/zero-terminated (subbytes raw 8 268))]
[Description (bytes->string/zero-terminated (subbytes raw 268 400))]
[Address (bytes->list (subbytes raw 404 410))]
[IpAddressList.IpAddress (bytes->string/zero-terminated (subbytes raw 432 448))]
[IpAddressList.IpMask (bytes->string/zero-terminated (subbytes raw 448 464))])
`((name . ,AdapterName)
(description . ,Description)
(address . ,Address)
(ip . ,IpAddressList.IpAddress)
(mask . ,IpAddressList.IpMask)))))
(define (current-network-adapters)
(let ([GetAdaptersInfo (get-ffi-obj 'GetAdaptersInfo "iphlpapi.dll"
(_fun _pointer _pointer -> _uint32))]
[pSize (malloc 4)])
(let loop ([size sizeof-IP_ADAPTER_INFO])
(let ([pAdapterInfo (malloc size)])
(ptr-set! pSize _uint32 size)
(let ([result (GetAdaptersInfo pAdapterInfo pSize)])
(cond
[(= result ERROR_BUFFER_OVERFLOW)
(free pAdapterInfo)
(loop (ptr-ref pSize _uint32))]
[(= result NO_ERROR)
(dynamic-wind
void
(lambda ()
(let loop ([p pAdapterInfo] [accum null])
(let ([info1 (adapter-info p)])
(if (zero? (ptr-ref p _uint32))
(cons info1 accum)
(loop (ptr-ref p _pointer) (cons info1 accum))))))
(lambda ()
(free pSize)
(free pAdapterInfo)))]
[else
(free pSize)
(free pAdapterInfo)
(error 'get-adapters-info (format "error number ~a" result))]))))))
(provide current-network-adapters))