blob: 6b5094163f8e2559414437e2c0ae9afc4526602c [file] [log] [blame]
package bluetooth
import (
"fmt"
"net"
"syscall"
"time"
)
// conn represents one RFCOMM connection between two bluetooth devices.
// It implements the net.Conn interface.
//
// TODO(ashankar,spetrovic): net.Conn implementations are supposed to be safe
// for concurrent method invocations. This implementation is not. Fix.
type conn struct {
fd int
localAddr, remoteAddr *addr
readDeadline time.Time
writeDeadline time.Time
}
func (c *conn) String() string {
return fmt.Sprintf("Bluetooth (%s) <--> (%s)", c.localAddr, c.remoteAddr)
}
// helper method for Read and Write that ensures:
// - the returned 'n' is always >= 0, as per guidelines for the io.Reader and
// io.Writer interfaces.
func (c *conn) rw(n int, err error) (int, error) {
if n < 0 {
n = 0
}
return n, err
}
// Implements the net.Conn interface.
func (c *conn) Read(p []byte) (n int, err error) {
return c.rw(syscall.Read(c.fd, p))
}
// Implements the net.Conn interface.
func (c *conn) Write(p []byte) (n int, err error) {
return c.rw(syscall.Write(c.fd, p))
}
// Implements the net.Conn interface.
func (c *conn) Close() error {
return syscall.Close(c.fd)
}
// Implements the net.Conn interface.
func (c *conn) LocalAddr() net.Addr {
return c.localAddr
}
// Implements the net.Conn interface.
func (c *conn) RemoteAddr() net.Addr {
return c.remoteAddr
}
// Implements the net.Conn interface.
func (c *conn) SetDeadline(t time.Time) error {
if err := c.SetReadDeadline(t); err != nil {
return err
}
if err := c.SetWriteDeadline(t); err != nil {
return err
}
return nil
}
// Implements the net.Conn interface.
func (c *conn) SetReadDeadline(t time.Time) error {
if timeout := getTimeout(t); timeout != nil {
return syscall.SetsockoptTimeval(c.fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, timeout)
}
return nil
}
// Implements the net.Conn interface.
func (c *conn) SetWriteDeadline(t time.Time) error {
if timeout := getTimeout(t); timeout != nil {
return syscall.SetsockoptTimeval(c.fd, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, timeout)
}
return nil
}
// getTimeout returns timeout for socket read/write operations, given the
// deadline specified as absolute time. Return value nil indicates no timeout.
// Return value 0 indicates that the read/write operation should timeout
// immediately.
func getTimeout(deadline time.Time) *syscall.Timeval {
if deadline.IsZero() {
return nil
}
d := deadline.Sub(time.Now())
if d < 0 {
ret := syscall.NsecToTimeval(0)
return &ret
}
ret := syscall.NsecToTimeval(d.Nanoseconds())
return &ret
}