Skip to content

Commit

Permalink
Use random port for application service
Browse files Browse the repository at this point in the history
  • Loading branch information
MadLittleMods committed Nov 6, 2021
1 parent 7ab71d4 commit 06935a7
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 4 deletions.
34 changes: 34 additions & 0 deletions internal/b/blueprints.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ import (
"crypto/rand"
"encoding/hex"
"fmt"
"net"
"strconv"
"strings"
)

var (
// HostnameRunningComplement is the hostname of Complement from the perspective of a Homeserver.
HostnameRunningComplement = "host.docker.internal"
)

// KnownBlueprints lists static blueprints
var KnownBlueprints = map[string]*Blueprint{
BlueprintCleanHS.Name: &BlueprintCleanHS,
Expand Down Expand Up @@ -190,6 +196,22 @@ func normaliseUser(u string, hsName string) (string, error) {
return u, nil
}

// Asks the kernel for a free open port that is ready to use.
// via https://github.com/phayes/freeport/blob/95f893ade6f232a5f1511d61735d89b1ae2df543/freeport.go#L7-L20
func getFreePort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}

l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}

func normalizeApplicationService(as ApplicationService) (ApplicationService, error) {
hsToken := make([]byte, 32)
_, err := rand.Read(hsToken)
Expand All @@ -206,6 +228,18 @@ func normalizeApplicationService(as ApplicationService) (ApplicationService, err
as.HSToken = hex.EncodeToString(hsToken)
as.ASToken = hex.EncodeToString(asToken)

if as.URL == "" {
// Since, we're just checking and not reserving the port, we could
// potentially run into an issue where the port is no longer available when
// we actually try to bind to it later on
port, err := getFreePort()
if err != nil {
return as, err
}

as.URL = fmt.Sprintf("http://%s:%d", HostnameRunningComplement, port)
}

return as, err
}

Expand Down
1 change: 0 additions & 1 deletion internal/b/hs_with_application_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ var BlueprintHSWithApplicationService = MustValidate(Blueprint{
ApplicationServices: []ApplicationService{
{
ID: "my_as_id",
URL: "http://host.docker.internal:9111",
SenderLocalpart: "the-bridge-user",
RateLimited: false,
},
Expand Down
26 changes: 23 additions & 3 deletions tests/msc2716_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"io/ioutil"
"net/http"
"net/url"
"regexp"
"testing"
"time"

Expand Down Expand Up @@ -60,6 +61,9 @@ var createPrivateRoomOpts = map[string]interface{}{
"room_version": "org.matrix.msc2716v3",
}

// Find the URL and port of the application service in some registration yaml text
var asURLRegexp = regexp.MustCompile(`url: '(.+):(\d+)'`)

func TestImportHistoricalMessages(t *testing.T) {
deployment := Deploy(t, b.BlueprintHSWithApplicationService)
defer deployment.Destroy(t)
Expand Down Expand Up @@ -312,6 +316,13 @@ func TestImportHistoricalMessages(t *testing.T) {
t.Run("Historical events from batch_send do not get pushed out as application service transactions", func(t *testing.T) {
t.Parallel()

asRegistration := deployment.HS["hs1"].ApplicationServices["my_as_id"]
asURLMatches := asURLRegexp.FindStringSubmatch(asRegistration)
if asURLMatches == nil {
t.Fatalf("Unable to find application service `url` in registration=%s", asRegistration)
}
asPort := asURLMatches[2]

// Create a listener and handler to stub an application service listening
// for transactions from a homeserver.
handler := mux.NewRouter()
Expand Down Expand Up @@ -343,13 +354,22 @@ func TestImportHistoricalMessages(t *testing.T) {
}).Methods("PUT")

srv := &http.Server{
Addr: ":9111",
Addr: fmt.Sprintf(":%s", asPort),
Handler: handler,
}
go func() {
srv.ListenAndServe()
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
// Note that running s.t.FailNow is not allowed in a separate goroutine
// Tests will likely fail if the server is not listening anyways
t.Logf("Failed to listen and serve our fake application service: %s", err)
}
}()
defer func() {
err := srv.Shutdown(context.Background())
if err != nil {
t.Fatalf("Failed to shutdown our fake application service: %s", err)
}
}()
defer srv.Shutdown(context.Background())
// ----------------------------------------------------------

// Create the room all of the action is going to happen in
Expand Down

0 comments on commit 06935a7

Please sign in to comment.