Code refactoring for HomeKit server
This commit is contained in:
@@ -49,7 +49,7 @@ func NewConsumer(conn net.Conn, server *srtp.Server) *Consumer {
|
||||
Connection: core.Connection{
|
||||
ID: core.NewID(),
|
||||
FormatName: "homekit",
|
||||
Protocol: "udp",
|
||||
Protocol: "rtp",
|
||||
RemoteAddr: conn.RemoteAddr().String(),
|
||||
Medias: medias,
|
||||
Transport: conn,
|
||||
@@ -59,6 +59,10 @@ func NewConsumer(conn net.Conn, server *srtp.Server) *Consumer {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Consumer) SessionID() string {
|
||||
return c.sessionID
|
||||
}
|
||||
|
||||
func (c *Consumer) SetOffer(offer *camera.SetupEndpointsRequest) {
|
||||
c.sessionID = offer.SessionID
|
||||
c.videoSession = &srtp.Session{
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Debug(v any) {
|
||||
switch v := v.(type) {
|
||||
case *http.Request:
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
if v.ContentLength != 0 {
|
||||
b, err := io.ReadAll(v.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
v.Body = io.NopCloser(bytes.NewReader(b))
|
||||
log.Printf("[homekit] request: %s %s\n%s", v.Method, v.RequestURI, b)
|
||||
} else {
|
||||
log.Printf("[homekit] request: %s %s <nobody>", v.Method, v.RequestURI)
|
||||
}
|
||||
case *http.Response:
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
if v.Header.Get("Content-Type") == "image/jpeg" {
|
||||
log.Printf("[homekit] response: %d <jpeg>", v.StatusCode)
|
||||
return
|
||||
}
|
||||
if v.ContentLength != 0 {
|
||||
b, err := io.ReadAll(v.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
v.Body = io.NopCloser(bytes.NewReader(b))
|
||||
log.Printf("[homekit] response: %s %d\n%s", v.Proto, v.StatusCode, b)
|
||||
} else {
|
||||
log.Printf("[homekit] response: %s %d <nobody>", v.Proto, v.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-15
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
@@ -34,24 +33,11 @@ type Client struct {
|
||||
}
|
||||
|
||||
func Dial(rawURL string, server *srtp.Server) (*Client, error) {
|
||||
u, err := url.Parse(rawURL)
|
||||
conn, err := hap.Dial(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := u.Query()
|
||||
conn := &hap.Client{
|
||||
DeviceAddress: u.Host,
|
||||
DeviceID: query.Get("device_id"),
|
||||
DevicePublic: hap.DecodeKey(query.Get("device_public")),
|
||||
ClientID: query.Get("client_id"),
|
||||
ClientPrivate: hap.DecodeKey(query.Get("client_private")),
|
||||
}
|
||||
|
||||
if err = conn.Dial(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
Connection: core.Connection{
|
||||
ID: core.NewID(),
|
||||
|
||||
+30
-24
@@ -4,31 +4,30 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/camera"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/hds"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/secure"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/tlv8"
|
||||
)
|
||||
|
||||
func ProxyHandler(pair ServerPair, dial func() (net.Conn, error)) hap.HandlerFunc {
|
||||
type ServerProxy interface {
|
||||
ServerPair
|
||||
AddConn(conn any)
|
||||
DelConn(conn any)
|
||||
}
|
||||
|
||||
func ProxyHandler(srv ServerProxy, acc net.Conn) HandlerFunc {
|
||||
return func(con net.Conn) error {
|
||||
defer con.Close()
|
||||
|
||||
acc, err := dial()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer acc.Close()
|
||||
|
||||
pr := &Proxy{
|
||||
con: con.(*secure.Conn),
|
||||
acc: acc.(*secure.Conn),
|
||||
con: con.(*hap.Conn),
|
||||
acc: acc.(*hap.Conn),
|
||||
res: make(chan *http.Response),
|
||||
}
|
||||
|
||||
@@ -36,17 +35,17 @@ func ProxyHandler(pair ServerPair, dial func() (net.Conn, error)) hap.HandlerFun
|
||||
go pr.handleAcc()
|
||||
|
||||
// controller => accessory
|
||||
return pr.handleCon(pair)
|
||||
return pr.handleCon(srv)
|
||||
}
|
||||
}
|
||||
|
||||
type Proxy struct {
|
||||
con *secure.Conn
|
||||
acc *secure.Conn
|
||||
con *hap.Conn
|
||||
acc *hap.Conn
|
||||
res chan *http.Response
|
||||
}
|
||||
|
||||
func (p *Proxy) handleCon(pair ServerPair) error {
|
||||
func (p *Proxy) handleCon(srv ServerProxy) error {
|
||||
var hdsCharIID uint64
|
||||
|
||||
rd := bufio.NewReader(p.con)
|
||||
@@ -61,7 +60,7 @@ func (p *Proxy) handleCon(pair ServerPair) error {
|
||||
switch {
|
||||
case req.Method == "POST" && req.URL.Path == hap.PathPairings:
|
||||
var res *http.Response
|
||||
if res, err = handlePairings(p.con, req, pair); err != nil {
|
||||
if res, err = handlePairings(req, srv); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = res.Write(p.con); err != nil {
|
||||
@@ -117,7 +116,7 @@ func (p *Proxy) handleCon(pair ServerPair) error {
|
||||
hdsPort := int(hdsRes.TransportTypeSessionParameters.TCPListeningPort)
|
||||
|
||||
// swtich accPort to conPort
|
||||
hdsPort, err = p.listenHDS(hdsPort, hdsConSalt+hdsAccSalt)
|
||||
hdsPort, err = p.listenHDS(srv, hdsPort, hdsConSalt+hdsAccSalt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -166,7 +165,8 @@ func (p *Proxy) handleAcc() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) listenHDS(accPort int, salt string) (int, error) {
|
||||
func (p *Proxy) listenHDS(srv ServerProxy, accPort int, salt string) (int, error) {
|
||||
// The TCP port range for HDS must be >= 32768.
|
||||
ln, err := net.ListenTCP("tcp", nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -175,30 +175,36 @@ func (p *Proxy) listenHDS(accPort int, salt string) (int, error) {
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
|
||||
_ = ln.SetDeadline(time.Now().Add(30 * time.Second))
|
||||
|
||||
// raw controller conn
|
||||
con, err := ln.Accept()
|
||||
conn1, err := ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer con.Close()
|
||||
|
||||
defer conn1.Close()
|
||||
|
||||
// secured controller conn (controlle=false because we are accessory)
|
||||
con, err = hds.Client(con, p.con.SharedKey, salt, false)
|
||||
con, err := hds.NewConn(conn1, p.con.SharedKey, salt, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
srv.AddConn(con)
|
||||
defer srv.DelConn(con)
|
||||
|
||||
accIP := p.acc.RemoteAddr().(*net.TCPAddr).IP
|
||||
|
||||
// raw accessory conn
|
||||
acc, err := net.Dial("tcp", fmt.Sprintf("%s:%d", accIP, accPort))
|
||||
conn2, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: accIP, Port: accPort})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer acc.Close()
|
||||
defer conn2.Close()
|
||||
|
||||
// secured accessory conn (controller=true because we are controller)
|
||||
acc, err = hds.Client(acc, p.acc.SharedKey, salt, true)
|
||||
acc, err := hds.NewConn(conn2, p.acc.SharedKey, salt, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+11
-46
@@ -15,15 +15,17 @@ import (
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/tlv8"
|
||||
)
|
||||
|
||||
type HandlerFunc func(net.Conn) error
|
||||
|
||||
type Server interface {
|
||||
ServerPair
|
||||
ServerAccessory
|
||||
}
|
||||
|
||||
type ServerPair interface {
|
||||
GetPair(conn net.Conn, id string) []byte
|
||||
AddPair(conn net.Conn, id string, public []byte, permissions byte)
|
||||
DelPair(conn net.Conn, id string)
|
||||
GetPair(id string) []byte
|
||||
AddPair(id string, public []byte, permissions byte)
|
||||
DelPair(id string)
|
||||
}
|
||||
|
||||
type ServerAccessory interface {
|
||||
@@ -33,11 +35,11 @@ type ServerAccessory interface {
|
||||
GetImage(conn net.Conn, width, height int) []byte
|
||||
}
|
||||
|
||||
func ServerHandler(server Server) hap.HandlerFunc {
|
||||
func ServerHandler(server Server) HandlerFunc {
|
||||
return handleRequest(func(conn net.Conn, req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case hap.PathPairings:
|
||||
return handlePairings(conn, req, server)
|
||||
return handlePairings(req, server)
|
||||
|
||||
case hap.PathAccessories:
|
||||
body := hap.JSONAccessories{Value: server.GetAccessories(conn)}
|
||||
@@ -103,7 +105,7 @@ func ServerHandler(server Server) hap.HandlerFunc {
|
||||
})
|
||||
}
|
||||
|
||||
func handleRequest(handle func(conn net.Conn, req *http.Request) (*http.Response, error)) hap.HandlerFunc {
|
||||
func handleRequest(handle func(conn net.Conn, req *http.Request) (*http.Response, error)) HandlerFunc {
|
||||
return func(conn net.Conn) error {
|
||||
rw := bufio.NewReaderSize(conn, 16*1024)
|
||||
wr := bufio.NewWriterSize(conn, 16*1024)
|
||||
@@ -130,7 +132,7 @@ func handleRequest(handle func(conn net.Conn, req *http.Request) (*http.Response
|
||||
}
|
||||
}
|
||||
|
||||
func handlePairings(conn net.Conn, req *http.Request, pair ServerPair) (*http.Response, error) {
|
||||
func handlePairings(req *http.Request, srv ServerPair) (*http.Response, error) {
|
||||
cmd := struct {
|
||||
Method byte `tlv8:"0"`
|
||||
Identifier string `tlv8:"1"`
|
||||
@@ -145,9 +147,9 @@ func handlePairings(conn net.Conn, req *http.Request, pair ServerPair) (*http.Re
|
||||
|
||||
switch cmd.Method {
|
||||
case 3: // add
|
||||
pair.AddPair(conn, cmd.Identifier, []byte(cmd.PublicKey), cmd.Permissions)
|
||||
srv.AddPair(cmd.Identifier, []byte(cmd.PublicKey), cmd.Permissions)
|
||||
case 4: // delete
|
||||
pair.DelPair(conn, cmd.Identifier)
|
||||
srv.DelPair(cmd.Identifier)
|
||||
}
|
||||
|
||||
body := struct {
|
||||
@@ -190,40 +192,3 @@ func makeResponse(mime string, v any) (*http.Response, error) {
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
//func debug(v any) {
|
||||
// switch v := v.(type) {
|
||||
// case *http.Request:
|
||||
// if v == nil {
|
||||
// return
|
||||
// }
|
||||
// if v.ContentLength != 0 {
|
||||
// b, err := io.ReadAll(v.Body)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// v.Body = io.NopCloser(bytes.NewReader(b))
|
||||
// log.Printf("[homekit] request: %s %s\n%s", v.Method, v.RequestURI, b)
|
||||
// } else {
|
||||
// log.Printf("[homekit] request: %s %s <nobody>", v.Method, v.RequestURI)
|
||||
// }
|
||||
// case *http.Response:
|
||||
// if v == nil {
|
||||
// return
|
||||
// }
|
||||
// if v.Header.Get("Content-Type") == "image/jpeg" {
|
||||
// log.Printf("[homekit] response: %d <jpeg>", v.StatusCode)
|
||||
// return
|
||||
// }
|
||||
// if v.ContentLength != 0 {
|
||||
// b, err := io.ReadAll(v.Body)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// v.Body = io.NopCloser(bytes.NewReader(b))
|
||||
// log.Printf("[homekit] response: %d\n%s", v.StatusCode, b)
|
||||
// } else {
|
||||
// log.Printf("[homekit] response: %d <nobody>", v.StatusCode)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user