Skip to content

Commit

Permalink
add client.go in adb dir
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Jan 4, 2019
1 parent 2486367 commit 01f76ed
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 25 deletions.
137 changes: 137 additions & 0 deletions adb/client.go
@@ -0,0 +1,137 @@
package adb

import (
"errors"
"fmt"
"io"
"net"
"strconv"
)

const (
// _OKAY = "OKAY"
_FAIL = "FAIL"
)

type ADBEncoder struct {
wr io.Writer
}

func (e *ADBEncoder) Encode(v []byte) error {
val := string(v)
data := fmt.Sprintf("%04x%s", len(val), val)
_, err := e.wr.Write([]byte(data))
return err
}

type ADBDecoder struct {
rd io.Reader
}

func (d *ADBDecoder) ReadN(n int) (data []byte, err error) {
buf := make([]byte, n)
_, err = io.ReadFull(d.rd, buf)
if err != nil {
return
}
return buf, nil
}

func (d *ADBDecoder) ReadNString(n int) (data string, err error) {
bdata, err := d.ReadN(n)
return string(bdata), err
}

func (d *ADBDecoder) DecodeString() (string, error) {
hexlen, err := d.ReadNString(4)
if err != nil {
return "", err
}
var length int
_, err = fmt.Sscanf(hexlen, "%04x", &length)
if err != nil {
return "", err
}
return d.ReadNString(length)
}

// respCheck check OKAY, or FAIL
func (d *ADBDecoder) respCheck() error {
status, err := d.ReadNString(4)
if err != nil {
return err
}
switch status {
case _OKAY:
return nil
case _FAIL:
data, err := d.DecodeString()
if err != nil {
return err
}
return errors.New(data)
default:
return fmt.Errorf("Unexpected response: %s, should be OKAY or FAIL", strconv.Quote(status))
}
}

func assembleString(data string) []byte {
pktData := fmt.Sprintf("%04x%s", len(data), data)
return []byte(pktData)
}

// func assembleBytes(data []byte) []byte {
// }

type Client struct {
Addr string
}

func NewClient(addr string) *Client {
return &Client{
Addr: addr,
}
}

// TODO(ssx): test not passed yet.
func (c *Client) Version() (string, error) {
conn, err := net.Dial("tcp", c.Addr)
if err != nil {
return "", err
}
writer := ADBEncoder{conn}
writer.Encode([]byte("host:version"))
reader := ADBDecoder{conn}
return reader.DecodeString()
}

func (c *Client) DeviceWithSerial(serial string) *ADevice {
return &ADevice{
client: c,
serial: serial,
}
}

// Device
type ADevice struct {
client *Client
serial string
}

func (ad *ADevice) OpenShell(cmd string) (rwc io.ReadWriteCloser, err error) {
return
}

func (ad *ADevice) Stat(path string) {

}

type PropValue string

func (p PropValue) Bool() bool {
return p == "true"
}

func (ad *ADevice) Properties() (props map[string]PropValue, err error) {
return
}
11 changes: 11 additions & 0 deletions adb/client_test.go
@@ -0,0 +1,11 @@
package adb

import "testing"

func TestVersion(t *testing.T) {
version, err := NewClient("127.0.0.1:5037").Version()
if err != nil {
t.Fatal(err)
}
t.Log(version)
}
25 changes: 15 additions & 10 deletions adb/packet.go
Expand Up @@ -31,29 +31,34 @@ func (pkt Packet) magic() []byte {
}

func (pkt Packet) checksum() uint32 {
return checksum(pkt.Body)
sum := uint32(0)
for _, c := range pkt.Body {
sum += uint32(c)
}
return sum
}

func (pkt Packet) swapu32(n uint32) uint32 {
var i uint32
buf := bytes.NewBuffer(nil)
binary.Write(buf, binary.LittleEndian, n)
binary.Read(buf, binary.BigEndian, &i)
return i
func (pkt Packet) length() uint32 {
return uint32(len(pkt.Body))
}

func (pkt Packet) BodySkipNull() []byte {
return bytes.TrimRight(pkt.Body, "\x00")
}

func (pkt Packet) EncodeToBytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, 24+len(pkt.Body)))
payload := pkt.Body // append(pkt.Body, byte(0x00))
buf := bytes.NewBuffer(make([]byte, 0, 24+pkt.length()))
if len(pkt.Command) != 4 {
panic("Invalid command " + strconv.Quote(pkt.Command))
}
binary.Write(buf, binary.LittleEndian, []byte(pkt.Command))
binary.Write(buf, binary.LittleEndian, pkt.Arg0)
binary.Write(buf, binary.LittleEndian, pkt.Arg1)
binary.Write(buf, binary.LittleEndian, uint32(len(pkt.Body)))
binary.Write(buf, binary.LittleEndian, pkt.length())
binary.Write(buf, binary.LittleEndian, pkt.checksum())
binary.Write(buf, binary.LittleEndian, pkt.magic())
buf.Write(pkt.Body)
buf.Write(payload)
return buf.Bytes()
}

Expand Down
55 changes: 42 additions & 13 deletions adb/tcpusb.go
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"log"
"net"
"strings"
)

type Session struct {
Expand Down Expand Up @@ -55,8 +56,8 @@ func (s *Session) handle() {
s.onConnection(pkt)
case _AUTH:
s.onAuth(pkt)
// case _OPEN:
// s.onOpen(pkt)
case _OPEN:
s.onOpen(pkt)
default:
log.Printf("unknown cmd: %s", pkt.Command)
return
Expand All @@ -66,6 +67,7 @@ func (s *Session) handle() {
break
}
}
log.Println("Session")
}

func (sess *Session) onConnection(pkt Packet) {
Expand All @@ -80,28 +82,53 @@ func (sess *Session) onConnection(pkt Packet) {
sess.maxPayload = maxPayload
log.Println("MaxPayload:", maxPayload)
sess.err = sess.writePacket(_AUTH, AUTH_TOKEN, 0, sess.token)
pkt.DumpToStdout()
}

func (sess *Session) authVerified() {
version := swapUint32(1)
log.Printf("send version: %x", version)
connProps := []string{
"ro.product.name=2014011",
"ro.product.model=2014011",
"ro.product.device=HM2014011",
}
// connProps = append(connProps, "features=cmd,stat_v2,shell_v2")
deviceBanner := "device"
payload := fmt.Sprintf("%s::%s", deviceBanner, strings.Join(connProps, ";"))
// id := "device::;;\x00"
sess.err = sess.writePacket(_CNXN, version, sess.maxPayload, []byte(payload))
Packet{_CNXN, sess.version, sess.maxPayload, []byte(payload)}.DumpToStdout()
}

func (sess *Session) onAuth(pkt Packet) {
log.Println("Handle AUTH")
switch pkt.Arg0 {
case AUTH_SIGNATURE:
sess.signature = pkt.Body
log.Printf("Receive signature: %x", base64.StdEncoding.EncodeToString(pkt.Body))
sess.err = sess.writePacket(_AUTH, AUTH_TOKEN, 0, sess.token)
// The real logic is
// If already have rsa_publickey, then verify signature, send CNXN if passed
// If no rsa pubkey, then send AUTH to request it
// Check signature again and send CNXN if passed
log.Printf("Receive signature: %s", base64.StdEncoding.EncodeToString(pkt.Body))
// sess.err = sess.writePacket(_AUTH, AUTH_TOKEN, 0, sess.token)
sess.authVerified()
case AUTH_RSAPUBLICKEY:
if sess.signature == nil {
sess.err = errors.New("Public key sent before signature")
return
}
log.Printf("Receive public key: %s", pkt.Body)
// TODO(ssx): parse public key from body and verify signature
// pkt.DumpToStdout()
log.Println("receive RSA PublicKey")
// pkt.DumpToStdout()
// send deviceId
log.Printf("send version: %x", sess.version)
id := "device::ro.product.name=2014011;ro.product.model=2014011;ro.product.device=HM2014011;\x00"
sess.err = sess.writePacket(_CNXN, sess.version, sess.maxPayload, []byte(id))
Packet{_CNXN, sess.version, sess.maxPayload, []byte(id)}.DumpToStdout()
// time.Sleep(10 * time.Second)
// sess.err = errors.New("retry")
// adb 1.0.40 will show "failed to authenticate to x.x.x.x:5555"
// but actually connected.
// sess.authVerified()
default:
sess.err = fmt.Errorf("unknown authentication method: %d", pkt.Arg0)
}
Expand All @@ -118,11 +145,13 @@ func RunAdbServer(serial string) error {
return err
}
defer lis.Close()
conn, err := lis.Accept()
if err != nil {
return err
for {
conn, err := lis.Accept()
if err != nil {
return err
}
sess := NewSession(conn)
go sess.handle()
}
sess := NewSession(conn)
sess.handle()
return nil
}
6 changes: 6 additions & 0 deletions adb/tcpusb_test.go
Expand Up @@ -5,8 +5,14 @@ import (
)

func TestTcpUsb(t *testing.T) {
t.Log("adb connect localhost:9000")
err := RunAdbServer("12345678")
if err != nil {
t.Fatal(err)
}
}

// func TestSliceBytes(t *testing.T) {
// buf := make([]byte, 0)
// t.Log(buf[0 : math.Max len(buf)-1])
// }
4 changes: 2 additions & 2 deletions tunnel/main.go
Expand Up @@ -20,8 +20,8 @@ func main() {
RemotePort: 8000,
Channel: make(chan int),
}
c.TargetHost = "10.246.46.160"
c.TargetPort = 8080
c.TargetHost = "127.0.0.1"
c.TargetPort = 6174

// Ref: https://github.com/labstack/tunnel-client/blob/master/cmd/root.go
res, err := resty.R().
Expand Down

0 comments on commit 01f76ed

Please sign in to comment.