github.com/apernet/sing-tun@v0.2.6-0.20240323130332-b9f6511036ad/internal/wintun/dll_windows.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package wintun 7 8 import ( 9 "fmt" 10 "sync" 11 "sync/atomic" 12 "unsafe" 13 14 "github.com/apernet/sing-tun/internal/wintun/memmod" 15 16 "golang.org/x/sys/windows" 17 ) 18 19 func (d *lazyDLL) NewProc(name string) *lazyProc { 20 return &lazyProc{dll: d, Name: name} 21 } 22 23 type lazyProc struct { 24 Name string 25 mu sync.Mutex 26 dll *lazyDLL 27 addr uintptr 28 } 29 30 func (p *lazyProc) Find() error { 31 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil { 32 return nil 33 } 34 p.mu.Lock() 35 defer p.mu.Unlock() 36 if p.addr != 0 { 37 return nil 38 } 39 40 err := p.dll.Load() 41 if err != nil { 42 return fmt.Errorf("error loading DLL: %s, MODULE: %s, error: %w", p.dll.Name, p.Name, err) 43 } 44 addr, err := p.nameToAddr() 45 if err != nil { 46 return fmt.Errorf("error getting %s address: %w", p.Name, err) 47 } 48 49 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr)) 50 return nil 51 } 52 53 func (p *lazyProc) Addr() uintptr { 54 err := p.Find() 55 if err != nil { 56 panic(err) 57 } 58 return p.addr 59 } 60 61 func (p *lazyProc) Load() error { 62 return p.dll.Load() 63 } 64 65 type lazyDLL struct { 66 Name string 67 Base windows.Handle 68 mu sync.Mutex 69 module *memmod.Module 70 } 71 72 func newLazyDLL(name string) *lazyDLL { 73 return &lazyDLL{Name: name} 74 } 75 76 func (d *lazyDLL) Load() error { 77 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil { 78 return nil 79 } 80 d.mu.Lock() 81 defer d.mu.Unlock() 82 if d.module != nil { 83 return nil 84 } 85 86 module, err := memmod.LoadLibrary(dllContent) 87 if err != nil { 88 return fmt.Errorf("unable to load library: %w", err) 89 } 90 d.Base = windows.Handle(module.BaseAddr()) 91 92 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module)) 93 return nil 94 } 95 96 func (p *lazyProc) nameToAddr() (uintptr, error) { 97 return p.dll.module.ProcAddressByName(p.Name) 98 }