blob: 591fef4416fe05f953a3702ab3c7e0cc36e9aa2c [file] [log] [blame]
package gateway
import (
"bytes"
"fmt"
"os/exec"
"strings"
"time"
"veyron2/vlog"
dbus "github.com/guelfey/go.dbus"
)
const (
agentPath = dbus.ObjectPath("/org/veyron/internal/lib/gateway/yesagent")
agentIface = "org.bluez.Agent"
)
var pingCmd = [][]string{
{"ping", "-i", "0.1", "-c", "3", "-w", "1.0", "-q"},
// TODO(spetrovic): Use Go's string libraries to reduce
// dependence on these tools.
{"grep", "rtt"},
{"cut", "-d", " ", "-f", "4"},
{"cut", "-d", "/", "-f", "2"},
{"awk", `{printf "%s", $NF}`},
}
func runPipedCmd(cmd [][]string) (string, error) {
if len(cmd) == 0 {
return "", fmt.Errorf("invalid command %q", cmd)
}
for _, c := range cmd {
if len(c) == 0 || len(c[0]) == 0 {
return "", fmt.Errorf("invalid command %q", cmd)
}
}
cs := make([]*exec.Cmd, len(cmd))
for i, c := range cmd {
cs[i] = exec.Command(c[0], c[1:]...)
}
for i := 1; i < len(cs); i++ {
var err error
if cs[i].Stdin, err = cs[i-1].StdoutPipe(); err != nil {
return "", fmt.Errorf("piping error: %v", err)
}
}
var out bytes.Buffer
cs[len(cs)-1].Stdout = &out
for _, c := range cs {
if err := c.Start(); err != nil {
return "", fmt.Errorf("error starting command %q: %q", c, err)
}
}
for _, c := range cs {
if err := c.Wait(); err != nil {
return "", fmt.Errorf("error executing command %q: %q", c, err)
}
}
return out.String(), nil
}
func ping(target string) (string, error) {
cmd := make([][]string, len(pingCmd))
copy(cmd, pingCmd)
cmd[0] = make([]string, len(pingCmd[0]))
copy(cmd[0], pingCmd[0])
cmd[0] = append(cmd[0], target)
return runPipedCmd(cmd)
}
func nameFromRTT(rtt time.Duration) string {
return fmt.Sprintf("NAP(%v)", rtt)
}
func rttFromName(name string) (time.Duration, error) {
if !strings.HasPrefix(name, "NAP(") || !strings.HasSuffix(name, ")") {
return 0, fmt.Errorf("invalid string %q", name)
}
d, err := time.ParseDuration(name[4 : len(name)-1])
if err != nil {
return 0, fmt.Errorf("couldn't parse RTT in name %q: %v", name, err)
}
return d, nil
}
// yesAgent implements the org.bluez.Agent DBus interface, allowing two devices
// to connect without any security. This DBus interface is compatible
// with bluez-4.101 package.
type yesAgent struct{}
func (*yesAgent) Release() *dbus.Error {
vlog.VI(1).Info("Release() called")
return nil
}
func (*yesAgent) RequestPinCode(device dbus.ObjectPath) (string, *dbus.Error) {
vlog.VI(1).Info("RequestPinCode(%q) called", device)
return "1234", nil
}
func (*yesAgent) RequestPasskey(device dbus.ObjectPath) (uint32, *dbus.Error) {
vlog.VI(1).Info("RequestPasskey(%q) called", device)
return 123456, nil
}
func (*yesAgent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint8) *dbus.Error {
vlog.VI(1).Info("DisplayPasskey(%q, %d, %d) called", device, passkey, entered)
return nil
}
func (*yesAgent) DisplayPinCode(device dbus.ObjectPath, pincode string) *dbus.Error {
vlog.VI(1).Info("DisplayPinCode(%q, %q) called", device, pincode)
return nil
}
func (*yesAgent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error {
vlog.VI(1).Info("RequestConfirmation(%q, %d) called", device, passkey)
return nil
}
func (*yesAgent) Authorize(device dbus.ObjectPath, uuid string) *dbus.Error {
vlog.VI(1).Info("AuthorizeService(%q, %q) called", device, uuid)
return nil
}
func (*yesAgent) ConfirmModeChange(mode string) *dbus.Error {
vlog.VI(1).Info("ConfirmModeChange(%q) called", mode)
return nil
}
func (*yesAgent) Cancel() *dbus.Error {
vlog.VI(1).Info("Cancel() called")
return nil
}