github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/qtls-go1-15/unsafe.go (about)

     1  package qtls
     2  
     3  import (
     4  	"crypto/tls"
     5  	"reflect"
     6  	"unsafe"
     7  )
     8  
     9  func init() {
    10  	if !structsEqual(&tls.ConnectionState{}, &connectionState{}) {
    11  		panic("qtls.ConnectionState doesn't match")
    12  	}
    13  	if !structsEqual(&tls.ClientSessionState{}, &clientSessionState{}) {
    14  		panic("qtls.ClientSessionState doesn't match")
    15  	}
    16  	if !structsEqual(&tls.Config{}, &config{}) {
    17  		panic("qtls.Config doesn't match")
    18  	}
    19  	if !structsEqual(&tls.ClientHelloInfo{}, &clientHelloInfo{}) {
    20  		panic("qtls.ClientHelloInfo doesn't match")
    21  	}
    22  }
    23  
    24  func toConnectionState(c connectionState) ConnectionState {
    25  	return *(*ConnectionState)(unsafe.Pointer(&c))
    26  }
    27  
    28  func toClientSessionState(s *clientSessionState) *ClientSessionState {
    29  	return (*ClientSessionState)(unsafe.Pointer(s))
    30  }
    31  
    32  func fromClientSessionState(s *ClientSessionState) *clientSessionState {
    33  	return (*clientSessionState)(unsafe.Pointer(s))
    34  }
    35  
    36  func toConfig(c *config) *Config {
    37  	return (*Config)(unsafe.Pointer(c))
    38  }
    39  
    40  func fromConfig(c *Config) *config {
    41  	return (*config)(unsafe.Pointer(c))
    42  }
    43  
    44  func toClientHelloInfo(chi *clientHelloInfo) *ClientHelloInfo {
    45  	return (*ClientHelloInfo)(unsafe.Pointer(chi))
    46  }
    47  
    48  func structsEqual(a, b interface{}) bool {
    49  	return compare(reflect.ValueOf(a), reflect.ValueOf(b))
    50  }
    51  
    52  func compare(a, b reflect.Value) bool {
    53  	sa := a.Elem()
    54  	sb := b.Elem()
    55  	if sa.NumField() != sb.NumField() {
    56  		return false
    57  	}
    58  	for i := 0; i < sa.NumField(); i++ {
    59  		fa := sa.Type().Field(i)
    60  		fb := sb.Type().Field(i)
    61  		if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
    62  			if fa.Type.Kind() != fb.Type.Kind() {
    63  				return false
    64  			}
    65  			if fa.Type.Kind() == reflect.Slice {
    66  				if !compareStruct(fa.Type.Elem(), fb.Type.Elem()) {
    67  					return false
    68  				}
    69  				continue
    70  			}
    71  			return false
    72  		}
    73  	}
    74  	return true
    75  }
    76  
    77  func compareStruct(a, b reflect.Type) bool {
    78  	if a.NumField() != b.NumField() {
    79  		return false
    80  	}
    81  	for i := 0; i < a.NumField(); i++ {
    82  		fa := a.Field(i)
    83  		fb := b.Field(i)
    84  		if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
    85  			return false
    86  		}
    87  	}
    88  	return true
    89  }