install go2rtc on bob

This commit is contained in:
2026-04-04 19:36:14 +02:00
parent f0b56e63d1
commit ccf88187b8
537 changed files with 69213 additions and 0 deletions
@@ -0,0 +1,218 @@
package homekit
import (
"bufio"
"bytes"
"encoding/json"
"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/tlv8"
)
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()
pr := &Proxy{
con: con.(*hap.Conn),
acc: acc.(*hap.Conn),
res: make(chan *http.Response),
}
// accessory (ex. Camera) => controller (ex. iPhone)
go pr.handleAcc()
// controller => accessory
return pr.handleCon(srv)
}
}
type Proxy struct {
con *hap.Conn
acc *hap.Conn
res chan *http.Response
}
func (p *Proxy) handleCon(srv ServerProxy) error {
var hdsCharIID uint64
rd := bufio.NewReader(p.con)
for {
req, err := http.ReadRequest(rd)
if err != nil {
return err
}
var hdsConSalt string
switch {
case req.Method == "POST" && req.URL.Path == hap.PathPairings:
var res *http.Response
if res, err = handlePairings(req, srv); err != nil {
return err
}
if err = res.Write(p.con); err != nil {
return err
}
continue
case req.Method == "PUT" && req.URL.Path == hap.PathCharacteristics && hdsCharIID != 0:
body, _ := io.ReadAll(req.Body)
var v hap.JSONCharacters
_ = json.Unmarshal(body, &v)
for _, char := range v.Value {
if char.IID == hdsCharIID {
var hdsReq camera.SetupDataStreamTransportRequest
_ = tlv8.UnmarshalBase64(char.Value, &hdsReq)
hdsConSalt = hdsReq.ControllerKeySalt
break
}
}
req.Body = io.NopCloser(bytes.NewReader(body))
}
if err = req.Write(p.acc); err != nil {
return err
}
res := <-p.res
switch {
case req.Method == "GET" && req.URL.Path == hap.PathAccessories:
body, _ := io.ReadAll(res.Body)
var v hap.JSONAccessories
if err = json.Unmarshal(body, &v); err != nil {
return err
}
for _, acc := range v.Value {
if char := acc.GetCharacter(camera.TypeSetupDataStreamTransport); char != nil {
hdsCharIID = char.IID
}
break
}
res.Body = io.NopCloser(bytes.NewReader(body))
case hdsConSalt != "":
body, _ := io.ReadAll(res.Body)
var v hap.JSONCharacters
_ = json.Unmarshal(body, &v)
for i, char := range v.Value {
if char.IID == hdsCharIID {
var hdsRes camera.SetupDataStreamTransportResponse
_ = tlv8.UnmarshalBase64(char.Value, &hdsRes)
hdsAccSalt := hdsRes.AccessoryKeySalt
hdsPort := int(hdsRes.TransportTypeSessionParameters.TCPListeningPort)
// swtich accPort to conPort
hdsPort, err = p.listenHDS(srv, hdsPort, hdsConSalt+hdsAccSalt)
if err != nil {
return err
}
hdsRes.TransportTypeSessionParameters.TCPListeningPort = uint16(hdsPort)
if v.Value[i].Value, err = tlv8.MarshalBase64(hdsRes); err != nil {
return err
}
body, _ = json.Marshal(v)
res.ContentLength = int64(len(body))
break
}
}
res.Body = io.NopCloser(bytes.NewReader(body))
}
if err = res.Write(p.con); err != nil {
return err
}
}
}
func (p *Proxy) handleAcc() error {
rd := bufio.NewReader(p.acc)
for {
res, err := hap.ReadResponse(rd, nil)
if err != nil {
return err
}
if res.Proto == hap.ProtoEvent {
if err = hap.WriteEvent(p.con, res); err != nil {
return err
}
continue
}
// important to read body before next read response
body, err := io.ReadAll(res.Body)
if err != nil {
return err
}
res.Body = io.NopCloser(bytes.NewReader(body))
p.res <- res
}
}
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
}
go func() {
defer ln.Close()
_ = ln.SetDeadline(time.Now().Add(30 * time.Second))
// raw controller conn
conn1, err := ln.Accept()
if err != nil {
return
}
defer conn1.Close()
// secured controller conn (controlle=false because we are accessory)
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
conn2, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: accIP, Port: accPort})
if err != nil {
return
}
defer conn2.Close()
// secured accessory conn (controller=true because we are controller)
acc, err := hds.NewConn(conn2, p.acc.SharedKey, salt, true)
if err != nil {
return
}
go io.Copy(con, acc)
_, _ = io.Copy(acc, con)
}()
conPort := ln.Addr().(*net.TCPAddr).Port
return conPort, nil
}