@@ -12,6 +12,7 @@ import (
1212 "net/http"
1313 "os"
1414 "runtime"
15+ "strconv"
1516 "strings"
1617 "time"
1718
@@ -103,7 +104,8 @@ func run(ctx context.Context, g *errgroup.Group, configuration *types.Configurat
103104 if err != nil {
104105 return err
105106 }
106- httpServe (ctx , g , ln , vn .Mux ())
107+
108+ httpServe (ctx , g , ln , muxWithExtension (vn ))
107109
108110 if opts .QemuSocket != "" {
109111 err = listenQEMU (ctx , vn )
@@ -239,6 +241,58 @@ func httpServe(ctx context.Context, g *errgroup.Group, ln net.Listener, mux http
239241 })
240242}
241243
244+ func muxWithExtension (n * virtualnetwork.VirtualNetwork ) * http.ServeMux {
245+ m := n .Mux ()
246+ m .HandleFunc ("/extension/wait_port" , func (w http.ResponseWriter , r * http.Request ) {
247+ ip := r .URL .Query ().Get ("ip" )
248+ if net .ParseIP (ip ) == nil {
249+ msg := fmt .Sprintf ("invalid ip address: %s" , ip )
250+ http .Error (w , msg , http .StatusBadRequest )
251+ return
252+ }
253+ port16 , err := strconv .ParseUint (r .URL .Query ().Get ("port" ), 10 , 16 )
254+ if err != nil {
255+ http .Error (w , err .Error (), http .StatusBadRequest )
256+ return
257+ }
258+ port := uint16 (port16 )
259+ addr := fmt .Sprintf ("%s:%d" , ip , port )
260+
261+ timeoutSeconds := 10
262+ if timeoutString := r .URL .Query ().Get ("timeout" ); timeoutString != "" {
263+ timeout16 , err := strconv .ParseUint (timeoutString , 10 , 16 )
264+ if err != nil {
265+ http .Error (w , err .Error (), http .StatusBadRequest )
266+ return
267+ }
268+ timeoutSeconds = int (timeout16 )
269+ }
270+ ctx , cancel := context .WithTimeout (context .Background (), time .Duration (timeoutSeconds )* time .Second )
271+ defer cancel ()
272+ // Wait until the port is available.
273+ for {
274+ conn , err := n .DialContextTCP (ctx , addr )
275+ if err == nil {
276+ conn .Close ()
277+ logrus .Debugf ("Port is available on %s" , addr )
278+ w .WriteHeader (http .StatusOK )
279+ break
280+ }
281+ select {
282+ case <- ctx .Done ():
283+ msg := fmt .Sprintf ("timed out waiting for port to become available on %s" , addr )
284+ logrus .Warn (msg )
285+ http .Error (w , msg , http .StatusRequestTimeout )
286+ return
287+ default :
288+ }
289+ logrus .Debugf ("Waiting for port to become available on %s" , addr )
290+ time .Sleep (1 * time .Second )
291+ }
292+ })
293+ return m
294+ }
295+
242296func searchDomains () []string {
243297 if runtime .GOOS != "windows" {
244298 return resolveSearchDomain ("/etc/resolv.conf" )
0 commit comments