-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglue.go
145 lines (117 loc) · 2.91 KB
/
glue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// CGo binding for Avahi
//
// Copyright (C) 2024 and up by Alexander Pevzner ([email protected])
// See LICENSE for license terms and conditions
//
// CGo glue
//
//go:build linux || freebsd
package avahi
import (
"net/netip"
"strconv"
"unsafe"
)
// #cgo pkg-config: avahi-client
//
// #include <avahi-client/client.h>
// #include <net/if.h>
import "C"
// makeAvahiAddress makes C.AvahiAddress
func makeAvahiAddress(addr netip.Addr) (C.AvahiAddress, error) {
var caddr C.AvahiAddress
addr = addr.Unmap()
switch {
case addr.Is4():
caddr.proto = C.AVAHI_PROTO_INET
(*(*[4]byte)(unsafe.Pointer(&caddr.data))) = addr.As4()
case addr.Is6():
caddr.proto = C.AVAHI_PROTO_INET6
(*(*[16]byte)(unsafe.Pointer(&caddr.data))) = addr.As16()
default:
return caddr, ErrInvalidAddress
}
return caddr, nil
}
// decodeAvahiAddress decodes C.AvahiAddress
func decodeAvahiAddress(ifindex IfIndex, caddr *C.AvahiAddress) netip.Addr {
var ip netip.Addr
switch {
case caddr == nil:
// Do nothing
case caddr.proto == C.AVAHI_PROTO_INET:
ip = netip.AddrFrom4(*(*[4]byte)(unsafe.Pointer(&caddr.data)))
case caddr.proto == C.AVAHI_PROTO_INET6:
ip = netip.AddrFrom16(*(*[16]byte)(unsafe.Pointer(&caddr.data)))
}
if ip.Is6() && ip.IsLinkLocalUnicast() {
ip = ip.WithZone(zoneName(ifindex))
}
return ip
}
// zoneName returns IPv6 zone name (which is the same as the
// network interface name) by interface index.
func zoneName(ifindex IfIndex) string {
var buf [C.IF_NAMESIZE]C.char
// Try if_indextoname
s := C.if_indextoname(C.uint(ifindex), &buf[0])
if s != nil {
return C.GoString(s)
}
// Fallback to numerical name. Go stdlib does the same.
return strconv.Itoa(int(ifindex))
}
// makeAvahiStringList makes C.AvahiStringList
func makeAvahiStringList(txt []string) (*C.AvahiStringList, error) {
var ctxt *C.AvahiStringList
for i := len(txt) - 1; i > 0; i-- {
b := []byte(txt[i])
prev := ctxt
ctxt = C.avahi_string_list_add_arbitrary(
ctxt,
(*C.uint8_t)(unsafe.Pointer(&b[0])),
C.size_t(len(b)),
)
if ctxt == nil {
C.avahi_string_list_free(prev)
return nil, ErrNoMemory
}
}
return ctxt, nil
}
// decodeAvahiStringList decodes C.AvahiStringList
func decodeAvahiStringList(ctxt *C.AvahiStringList) []string {
var txt []string
for ctxt != nil {
t := C.GoStringN((*C.char)(unsafe.Pointer(&ctxt.text)),
C.int(ctxt.size))
txt = append(txt, t)
ctxt = ctxt.next
}
return txt
}
// strcaseequal compares two strings ignoring case, as C does,
// i.e. without any special interpretation of UTF-8 sequences.
func strcaseequal(s1, s2 string) bool {
if len(s1) != len(s2) {
return false
}
for i := 0; i < len(s1); i++ {
c1 := s1[i]
c2 := s2[i]
switch {
case c1 == c2:
case toupper(c1) == toupper(c2):
default:
return false
}
}
return true
}
// toupper converts ASCII character to uppercase
func toupper(c byte) byte {
if 'a' <= c && c <= 'z' {
c = c - 'a' + 'A'
}
return c
}