From 7d37f645ba667d536263f0c7e1aa058880034886 Mon Sep 17 00:00:00 2001 From: Alex X Date: Tue, 25 Feb 2025 16:42:18 +0300 Subject: [PATCH] Improved limited HomeKit server support for open source projects --- internal/homekit/homekit.go | 54 ++++++++++++++++++++----------------- pkg/hap/server_pairing.go | 15 +++++++++++ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/internal/homekit/homekit.go b/internal/homekit/homekit.go index 632607d4..b4237211 100644 --- a/internal/homekit/homekit.go +++ b/internal/homekit/homekit.go @@ -118,8 +118,8 @@ func Init() { servers[host] = srv } - api.HandleFunc(hap.PathPairSetup, hapPairSetup) - api.HandleFunc(hap.PathPairVerify, hapPairVerify) + api.HandleFunc(hap.PathPairSetup, hapHandler) + api.HandleFunc(hap.PathPairVerify, hapHandler) log.Trace().Msgf("[homekit] mdns: %s", entries) @@ -148,32 +148,19 @@ func streamHandler(rawURL string) (core.Producer, error) { return client, err } -func hapPairSetup(w http.ResponseWriter, r *http.Request) { - srv, ok := servers[r.Host] - if !ok { - log.Error().Msg("[homekit] unknown host: " + r.Host) - return +func resolve(host string) *server { + if len(servers) == 1 { + for _, srv := range servers { + return srv + } } - - conn, rw, err := w.(http.Hijacker).Hijack() - if err != nil { - return - } - - defer conn.Close() - - if err = srv.hap.PairSetup(r, rw, conn); err != nil { - log.Error().Err(err).Caller().Send() + if srv, ok := servers[host]; ok { + return srv } + return nil } -func hapPairVerify(w http.ResponseWriter, r *http.Request) { - srv, ok := servers[r.Host] - if !ok { - log.Error().Msg("[homekit] unknown host: " + r.Host) - return - } - +func hapHandler(w http.ResponseWriter, r *http.Request) { conn, rw, err := w.(http.Hijacker).Hijack() if err != nil { return @@ -181,7 +168,24 @@ func hapPairVerify(w http.ResponseWriter, r *http.Request) { defer conn.Close() - if err = srv.hap.PairVerify(r, rw, conn); err != nil && err != io.EOF { + // Can support multiple HomeKit cameras on single port ONLY for Apple devices. + // Doesn't support Home Assistant and any other open source projects + // because they don't send the host header in requests. + srv := resolve(r.Host) + if srv == nil { + log.Error().Msg("[homekit] unknown host: " + r.Host) + _ = hap.WriteBackoff(rw) + return + } + + switch r.RequestURI { + case hap.PathPairSetup: + err = srv.hap.PairSetup(r, rw, conn) + case hap.PathPairVerify: + err = srv.hap.PairVerify(r, rw, conn) + } + + if err != nil && err != io.EOF { log.Error().Err(err).Caller().Send() } } diff --git a/pkg/hap/server_pairing.go b/pkg/hap/server_pairing.go index 31d2f626..77895c10 100644 --- a/pkg/hap/server_pairing.go +++ b/pkg/hap/server_pairing.go @@ -235,3 +235,18 @@ func WriteResponse(w *bufio.Writer, statusCode int, contentType string, body []b } return w.Flush() } + +func WriteBackoff(rw *bufio.ReadWriter) error { + plainM2 := struct { + State byte `tlv8:"6"` + Error byte `tlv8:"7"` + }{ + State: StateM2, + Error: 3, // BackoffError + } + body, err := tlv8.Marshal(plainM2) + if err != nil { + return err + } + return WriteResponse(rw.Writer, http.StatusOK, MimeTLV8, body) +}