blob: ffc49a6aefc5677672277cc67e482d95dad9a88f [file] [log] [blame]
// 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))
}