forked from cksmith/gatt
/
socket.go
121 lines (103 loc) · 2.48 KB
/
socket.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
// Package socket implements a minimal set of function of the HCI Socket,
// which is not yet supported by the Go standard library. Most of the code
// follow suit the existing code in the standard library. Once it gets
// supported officially, we can get rid of this package entirely.
package socket
import (
"errors"
"syscall"
"time"
"unsafe"
)
// Bluetooth Protocols
const (
BTPROTO_L2CAP = 0
BTPROTO_HCI = 1
BTPROTO_SCO = 2
BTPROTO_RFCOMM = 3
BTPROTO_BNEP = 4
BTPROTO_CMTP = 5
BTPROTO_HIDP = 6
BTPROTO_AVDTP = 7
)
const (
HCI_CHANNEL_RAW = 0
HCI_CHANNEL_USER = 1
HCI_CHANNEL_MONITOR = 2
HCI_CHANNEL_CONTROL = 3
)
var (
ErrSocketOpenFailed = errors.New("unable to open bluetooth socket to device")
ErrSocketBindTimeout = errors.New("timeout occured binding to bluetooth device")
)
type _Socklen uint32
type Sockaddr interface {
sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}
type rawSockaddrHCI struct {
Family uint16
Dev uint16
Channel uint16
}
type SockaddrHCI struct {
Dev int
Channel uint16
raw rawSockaddrHCI
}
const sizeofSockaddrHCI = unsafe.Sizeof(rawSockaddrHCI{})
func (sa *SockaddrHCI) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Dev < 0 || sa.Dev > 0xFFFF {
return nil, 0, syscall.EINVAL
}
if sa.Channel < 0 || sa.Channel > 0xFFFF {
return nil, 0, syscall.EINVAL
}
sa.raw.Family = AF_BLUETOOTH
sa.raw.Dev = uint16(sa.Dev)
sa.raw.Channel = sa.Channel
return unsafe.Pointer(&sa.raw), _Socklen(sizeofSockaddrHCI), nil
}
func Socket(domain, typ, proto int) (int, error) {
for i := 0; i < 5; i++ {
if fd, err := syscall.Socket(domain, typ, proto); err == nil || err != syscall.EBUSY {
return fd, err
}
time.Sleep(time.Second)
}
return 0, ErrSocketOpenFailed
}
func Bind(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
if err != nil {
return err
}
for i := 0; i < 5; i++ {
if err = bind(fd, ptr, n); err == nil || err != syscall.EBUSY {
return err
}
time.Sleep(time.Second)
}
return ErrSocketBindTimeout
}
// Socket Level
const (
SOL_HCI = 0
SOL_L2CAP = 6
SOL_SCO = 17
SOL_RFCOMM = 18
SOL_BLUETOOTH = 274
)
// HCI Socket options
const (
HCI_DATA_DIR = 1
HCI_FILTER = 2
HCI_TIME_STAMP = 3
)
type HCIFilter struct {
TypeMask uint32
EventMask [2]uint32
opcode uint16
}
func SetsockoptFilter(fd int, f *HCIFilter) (err error) {
return setsockopt(fd, SOL_HCI, HCI_FILTER, unsafe.Pointer(f), unsafe.Sizeof(*f))
}