func (vm *KvmVM) connectVNC() error { l, err := net.Listen("tcp", "") if err != nil { return err } // Keep track of shim so that we can close it later vm.vncShim = l vm.VNCPort = l.Addr().(*net.TCPAddr).Port ns := fmt.Sprintf("%v:%v", vm.Namespace, vm.Name) go func() { defer l.Close() for { // Sit waiting for new connections remote, err := l.Accept() if err != nil && strings.Contains(err.Error(), "use of closed network connection") { return } else if err != nil { log.Errorln(err) return } go func() { defer remote.Close() // Dial domain socket local, err := net.Dial("unix", vm.path("vnc")) if err != nil { log.Error("unable to dial vm vnc: %v", err) return } defer local.Close() // copy local -> remote go io.Copy(remote, local) // Reads will implicitly copy from remote -> local tee := io.TeeReader(remote, local) for { // Read msg, err := vnc.ReadClientMessage(tee) if err != nil { if err == io.EOF || strings.Contains(err.Error(), "closed network") { break } log.Errorln(err) } if r, ok := vncKBRecording[ns]; ok { r.RecordMessage(msg) } } }() } }() return nil }
func vncWsHandler(w http.ResponseWriter, r *http.Request) { // we assume that if we got here, then the url must be sane and of // the format /ws/<host>/<port> path := r.URL.Path if !strings.HasSuffix(path, "/") { path += "/" } fields := strings.Split(path, "/") if len(fields) != 5 { http.NotFound(w, r) return } fields = fields[2:] rhost := fmt.Sprintf("%v:%v", fields[0], fields[1]) // connect to the remote host remote, err := net.Dial("tcp", rhost) if err != nil { log.Errorln(err) http.StatusText(500) return } websocket.Handler(func(ws *websocket.Conn) { go func() { decoder := base64.NewDecoder(base64.StdEncoding, ws) tee := io.TeeReader(decoder, remote) for { // Read msg, err := vnc.ReadClientMessage(tee) if err != nil { if err == io.EOF || strings.Contains(err.Error(), "closed network") { break } log.Debugln(err) continue } if r, ok := vncKBRecording[rhost]; ok { r.RecordMessage(msg) } } remote.Close() }() func() { sbuf := make([]byte, VNC_WS_BUF) dbuf := make([]byte, 2*VNC_WS_BUF) for { n, err := remote.Read(sbuf) if err != nil { if !strings.Contains(err.Error(), "closed network connection") && err != io.EOF { log.Errorln(err) } break } base64.StdEncoding.Encode(dbuf, sbuf[0:n]) n = base64.StdEncoding.EncodedLen(n) _, err = ws.Write(dbuf[0:n]) if err != nil { log.Errorln(err) break } } ws.Close() }() }).ServeHTTP(w, r) }