Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/release-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,12 @@ jobs:
cli/dist/conduit-linux-arm64
cli/dist/conduit-linux-armv7
cli/dist/conduit-linux-armv6
cli/dist/conduit-linux-386
cli/dist/conduit-monitor-linux-amd64
cli/dist/conduit-monitor-linux-arm64
cli/dist/conduit-monitor-linux-armv7
cli/dist/conduit-monitor-linux-armv6
cli/dist/conduit-monitor-linux-386
cli/dist/checksums.txt

- name: Create Release
Expand All @@ -130,6 +132,7 @@ jobs:
cli/dist/conduit-linux-arm64
cli/dist/conduit-linux-armv7
cli/dist/conduit-linux-armv6
cli/dist/conduit-linux-386
cli/dist/conduit-darwin-amd64
cli/dist/conduit-darwin-arm64
cli/dist/conduit-windows-amd64.exe
Expand Down
16 changes: 12 additions & 4 deletions cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ PSIPHON_REPO := https://github.com/Psiphon-Labs/psiphon-tunnel-core.git
# $(3) = GOOS
# $(4) = GOARCH
# $(5) = GOARM (optional)
# $(6) = extra env vars (optional, e.g. GO386=softfloat)
define GO_BUILD
@BUILDDATE=$$(date +%Y-%m-%dT%H:%M:%S%z) && \
BUILDREPO=$$(cd psiphon-tunnel-core && git config --get remote.origin.url) && \
BUILDREV=$$(cd psiphon-tunnel-core && git rev-parse --short HEAD) && \
GOVERSION="$$($(GO) version | sed 's/go version //')" && \
ALL_TAGS="$(BASE_TAGS)" && \
if [ -n "$(2)" ]; then ALL_TAGS="$$ALL_TAGS,$(2)"; fi && \
if [ -n "$(2)" ]; then ALL_TAGS="$$ALL_TAGS $(2)"; fi && \
echo "Building $(3)/$(4) -> $(1) with tags: $$ALL_TAGS" && \
CGO_ENABLED=0 GOOS=$(3) GOARCH=$(4) $(if $(5),GOARM=$(5)) $(GO) build \
CGO_ENABLED=0 GOOS=$(3) GOARCH=$(4) $(if $(5),GOARM=$(5)) $(if $(6),$(6)) $(GO) build \
-tags "$$ALL_TAGS" \
-ldflags "\
-s -w \
Expand All @@ -50,9 +51,10 @@ endef
# $(2) = GOOS
# $(3) = GOARCH
# $(4) = GOARM (optional)
# $(5) = extra env vars (optional, e.g. GO386=softfloat)
define GO_BUILD_MONITOR
@echo "Building monitor $(2)/$(3) -> $(1)"
@CGO_ENABLED=0 GOOS=$(2) GOARCH=$(3) $(if $(4),GOARM=$(4)) $(GO) build \
@CGO_ENABLED=0 GOOS=$(2) GOARCH=$(3) $(if $(4),GOARM=$(4)) $(if $(5),$(5)) $(GO) build \
-ldflags "-s -w" \
-o $(1) ./scripts/monitor
endef
Expand Down Expand Up @@ -133,6 +135,10 @@ build-linux-armv6: check-go check-setup
$(call GO_BUILD,dist/conduit-linux-armv6,,linux,arm,6)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-linux-armv6,linux,arm,6)

build-linux-386: check-go check-setup
$(call GO_BUILD,dist/conduit-linux-386,netgo,linux,386,,GO386=softfloat)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-linux-386,linux,386,,GO386=softfloat)

build-darwin: check-go check-setup
$(call GO_BUILD,dist/conduit-darwin-amd64,,darwin,amd64)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-darwin-amd64,darwin,amd64)
Expand All @@ -150,7 +156,7 @@ build-freebsd: check-go check-setup
$(call GO_BUILD_MONITOR,dist/conduit-monitor-freebsd-amd64,freebsd,amd64)

# Build for all platforms
build-all: check-go check-setup build-linux build-linux-arm build-linux-armv7 build-linux-armv6 build-darwin build-darwin-arm build-windows build-freebsd
build-all: check-go check-setup build-linux build-linux-arm build-linux-armv7 build-linux-armv6 build-linux-386 build-darwin build-darwin-arm build-windows build-freebsd

# Build for all platforms with embedded config
build-all-embedded: check-go check-setup check-psiphon-config
Expand All @@ -160,6 +166,7 @@ build-all-embedded: check-go check-setup check-psiphon-config
$(call GO_BUILD,dist/conduit-linux-arm64,$(EMBED_TAG),linux,arm64)
$(call GO_BUILD,dist/conduit-linux-armv7,$(EMBED_TAG),linux,arm,7)
$(call GO_BUILD,dist/conduit-linux-armv6,$(EMBED_TAG),linux,arm,6)
$(call GO_BUILD,dist/conduit-linux-386,$(EMBED_TAG) netgo,linux,386,,GO386=softfloat)
$(call GO_BUILD,dist/conduit-darwin-amd64,$(EMBED_TAG),darwin,amd64)
$(call GO_BUILD,dist/conduit-darwin-arm64,$(EMBED_TAG),darwin,arm64)
$(call GO_BUILD,dist/conduit-windows-amd64.exe,$(EMBED_TAG),windows,amd64)
Expand All @@ -170,6 +177,7 @@ build-all-embedded: check-go check-setup check-psiphon-config
$(call GO_BUILD_MONITOR,dist/conduit-monitor-linux-arm64,linux,arm64)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-linux-armv7,linux,arm,7)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-linux-armv6,linux,arm,6)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-linux-386,linux,386,,GO386=softfloat)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-darwin-amd64,darwin,amd64)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-darwin-arm64,darwin,arm64)
$(call GO_BUILD_MONITOR,dist/conduit-monitor-windows-amd64.exe,windows,amd64)
Expand Down
13 changes: 13 additions & 0 deletions cli/cmd/ish_linux_386.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build linux && 386

package cmd

import "runtime"

func init() {
// iSH's %gs TLS emulation is unreliable in signal handler context. With
// multiple Ps, Go sends SIGURG to preempt goroutines across OS threads,
// which triggers a "bad g in signal handler" crash. GOMAXPROCS=1 keeps
// all goroutines on a single P, preventing cross-thread SIGURG delivery.
runtime.GOMAXPROCS(1)
}
47 changes: 37 additions & 10 deletions src/hosted/sessionQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,48 @@ export async function ensureHostedSession(
return refreshHostedSession(queryClient, input);
}

// Deduplicates concurrent refresh calls for the same queryClient+baseUrl so
// that parallel queries racing on an expiring token only trigger one network
// request. WeakMap keying avoids cross-test pollution.
const inflightRefreshes = new WeakMap<
QueryClient,
Map<string, Promise<HostedSession>>
>();

export async function refreshHostedSession(
queryClient: QueryClient,
input: HostedSessionDependencies,
): Promise<HostedSession> {
try {
const refreshed = await input.sessionClient.refresh();
await setHostedSessionState(queryClient, input, refreshed);
return refreshed;
} catch (error) {
if (error instanceof HostedApiRequestError && error.status === 401) {
await clearHostedSessionState(queryClient, input);
throw new Error("Hosted session expired; please sign in again");
}
throw error;
let byUrl = inflightRefreshes.get(queryClient);
if (!byUrl) {
byUrl = new Map();
inflightRefreshes.set(queryClient, byUrl);
}

const existing = byUrl.get(input.baseUrl);
if (existing) return existing;

const promise = (async () => {
try {
const refreshed = await input.sessionClient.refresh();
await setHostedSessionState(queryClient, input, refreshed);
return refreshed;
} catch (error) {
if (
error instanceof HostedApiRequestError &&
error.status === 401
) {
await clearHostedSessionState(queryClient, input);
throw new Error("Hosted session expired; please sign in again");
}
throw error;
} finally {
byUrl.delete(input.baseUrl);
}
})();

byUrl.set(input.baseUrl, promise);
return promise;
}

export async function withHostedSessionRecovery<T>(
Expand Down