blob: 69e33a325d1cdddd657e5285ecb7dfc83bed265b [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package util
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"strconv"
"strings"
"sync"
"syscall"
)
func StartV23ServerProxy(v23ProxyRoot string) (*V23ProxyController, error) {
cmd := RunMojoShellForV23ProxyTests("v23serverproxy.mojo", v23ProxyRoot, []string{"--v23.tcp.address=127.0.0.1:0"})
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, err
}
go func() {
io.Copy(os.Stderr, stderr)
}()
// A lock is put in home for the url response cache. Change HOME for v23proxy, since
// two mojo shells will be run.
tempHome, err := ioutil.TempDir("", "")
if err != nil {
return nil, err
}
cmd.Env = append(cmd.Env, "HOME="+tempHome)
if err := cmd.Start(); err != nil {
return nil, err
}
return &V23ProxyController{
cmd: cmd,
stdout: stdout,
tempHome: tempHome,
}, nil
}
type V23ProxyController struct {
cmd *exec.Cmd
stdout io.ReadCloser
endpointLock sync.Mutex
endpoint string // empty until the endpoint is read
tempHome string
}
func (v *V23ProxyController) Stop() error {
os.Remove(v.tempHome)
childPids, err := getChildProcessPids(v.cmd.Process.Pid)
if err != nil {
return err
}
if err := v.cmd.Process.Signal(syscall.SIGTERM); err != nil {
return err
}
for _, pid := range childPids {
syscall.Kill(pid, syscall.SIGTERM)
}
return nil
}
func (v *V23ProxyController) Endpoint() (string, error) {
v.endpointLock.Lock()
defer v.endpointLock.Unlock()
if v.endpoint != "" {
return v.endpoint, nil
}
scanner := bufio.NewScanner(v.stdout)
const prefix = "Listening at: "
for scanner.Scan() {
if strings.HasPrefix(scanner.Text(), prefix) {
v.endpoint = strings.TrimPrefix(scanner.Text(), prefix)
return v.endpoint, nil
}
}
if err := scanner.Err(); err != nil {
return "", err
}
return "", fmt.Errorf("unexpected EOF when looking for endpoint")
}
func getChildProcessPids(parentPid int) ([]int, error) {
cmd := exec.Command("ps", []string{"h", "--ppid", fmt.Sprintf("%d", parentPid), "-o", "pid"}...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(stdout)
var pids []int
if err := cmd.Start(); err != nil {
return nil, err
}
for scanner.Scan() {
if len(scanner.Text()) == 0 {
continue
}
pid, err := strconv.ParseInt(strings.Trim(scanner.Text(), " "), 10, 64)
if err != nil {
return nil, err
}
pids = append(pids, int(pid))
}
return pids, cmd.Wait()
}