github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/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/metacubex/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  }