Skip to content

Commit

Permalink
hcsshim hvsock loopback server to sidecar communication working
Browse files Browse the repository at this point in the history
Signed-off-by: Kirtana Ashok <[email protected]>
  • Loading branch information
kiashok committed Sep 23, 2024
1 parent 0d3b0f7 commit 131ff98
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 27 deletions.
198 changes: 171 additions & 27 deletions cmd/gcs-sidecar/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ package main
import (
"context"
"fmt"
"log"
"os"
"time"

"github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/gcs"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/debug"
)

var WindowsSidecarGcsHvsockServiceID = guid.GUID{
Expand All @@ -21,40 +24,30 @@ var WindowsSidecarGcsHvsockServiceID = guid.GUID{
Data4: [8]uint8{0xa5, 0x2b, 0x90, 0x2b, 0xc0, 0xfa, 0x04, 0x11},
}

// [guid]::NewGuid()
// sidecar gcs GUID
// new guid for my service
// ae8da506-a019-4553-a52b-902bc0fa0411

// Option 1 sidecar before GCS
func main() {
addr := &winio.HvsockAddr{
VMID: gcs.HV_GUID_PARENT,
ServiceID: WindowsSidecarGcsHvsockServiceID,
}

d := &winio.HvsockDialer{
Deadline: time.Now().Add(10 * time.Minute),
Retries: 1000,
RetryWait: time.Second,
}
type hvSockDetails struct {
hvsockAddr *winio.HvsockAddr
hvsockDialer *winio.HvsockDialer
}

// file to record the logs
file, err := os.OpenFile("sidecar-gcs-logs.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("Error opening file: %v", err)
return
}
defer file.Close()
type handler struct {
hvsockAddrAndDialer *hvSockDetails
fromsvc chan error
}

func (hv *hvSockDetails) startRecvAndSendLoop() {
log.Printf("Starting startRecvAndSendLoop() with %v", hv)
ctx := context.Background()
hvsockCon, err := d.Dial(ctx, addr)
hvsockCon, err := hv.hvsockDialer.Dial(ctx, hv.hvsockAddr)
if err != nil {
// error dialing the address
_, _ = file.WriteString(fmt.Sprintf("Error dialing hvsock sidecar listener at address %v", addr))
log.Printf("Error dialing hvsock sidecar listener at address %v", hv.hvsockAddr)
return
}

go sendToHvSocketListener(hvsockCon, file)
go sendToHvSocketListener(hvsockCon)

// TODO: start the server for GCS bridge client to connect to.
// 1. use named pipes for communication
Expand All @@ -72,12 +65,13 @@ func main() {
*/
}

func sendToHvSocketListener(hvsockCon *winio.HvsockConn, file *os.File) {
func sendToHvSocketListener(hvsockCon *winio.HvsockConn) {
log.Printf("Starting sendToHvSocketListener() with connection %v", hvsockCon)
// write data
for {
_, err := hvsockCon.Write([]byte(fmt.Sprintf("!! From sidecar GCS at time %v", time.Now())))
_, err := hvsockCon.Write([]byte(fmt.Sprintf("!! Hello from sidecar GCS at time %v \n", time.Now())))
if err != nil {
file.WriteString(fmt.Sprintf("!! Error writing to sidecar GCS at time %v", time.Now()))
log.Printf("!! Error writing to sidecar GCS at time %v", time.Now())
return
}
// any delay
Expand All @@ -87,3 +81,153 @@ func sendToHvSocketListener(hvsockCon *winio.HvsockConn, file *os.File) {

// TODO: code for option 2 - inbox GCS calls into sidecar executable through named pipes OR
// register callbacks and made it call into it?

func (m *handler) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
log.Printf("got execute request \n ")
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue

status <- svc.Status{State: svc.StartPending}
//m.hvsockAddrAndDialer.startRecvAndSendLoop()
// tick := time.Tick(5 * time.Second)
m.fromsvc <- nil
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}

loop:
for {
select {
// case <-tick:
// log.Print("Tick Handled...!")
// log.Printf("counter is %v", (m.counter))
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
status <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
log.Print("Shutting service...!")
break loop
case svc.Pause:
status <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
case svc.Continue:
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
default:
log.Printf("Unexpected service control request #%d", c)
}
}
}

status <- svc.Status{State: svc.StopPending}
return false, 1
}

func runService(name string, isDebug bool, hvsockAddr *winio.HvsockAddr, hvsockDialer *winio.HvsockDialer) error {
h := &handler{
hvsockAddrAndDialer: &hvSockDetails{
hvsockAddr: hvsockAddr,
hvsockDialer: hvsockDialer,
},
fromsvc: make(chan error),
}

var err error
go func() {
if isDebug {
err := debug.Run(name, h)
if err != nil {
log.Fatalf("Error running service in debug mode.Err: %v", err)
}
} else {
err := svc.Run(name, h)
if err != nil {
log.Fatalf("Error running service in Service Control mode.Err %v", err)
}
}
h.fromsvc <- err
}()

// Wait for the first signal from the service handler.
log.Printf("waiting for first signal from scm \n")
err = <-h.fromsvc
if err != nil {
return err
}
return nil

}

// [guid]::NewGuid()
// sidecar gcs GUID
// ae8da506-a019-4553-a52b-902bc0fa0411

// Option 1 sidecar before GCS

func main() {
f, err := os.OpenFile("C:/service-debug-gcs-sidecar.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("error opening file: %v", err)
log.Fatalln(fmt.Errorf("error opening file: %v", err))
}
defer f.Close()

log.SetOutput(f)

//

type srvResp struct {
srvDetails *hvSockDetails
// // /err error
}
//
chsrv := make(chan srvResp)
go func() {
defer close(chsrv)

hvsockAddr := &winio.HvsockAddr{
VMID: gcs.HV_GUID_LOOPBACK, // HV_GUID_PARENT
ServiceID: WindowsSidecarGcsHvsockServiceID,
}

hcsockDialer := &winio.HvsockDialer{
Deadline: time.Now().Add(10 * time.Minute),
Retries: 1000,
RetryWait: time.Second,
}

if err := runService("gcs-sidecar", false, hvsockAddr, hcsockDialer); err != nil {
log.Fatal(err)
}

//hv := &hvSockDetails{hvsockAddr: hvsockAddr, hvsockDialer: hcsockDialer}
select {
case chsrv <- srvResp{srvDetails: &hvSockDetails{hvsockAddr: hvsockAddr, hvsockDialer: hcsockDialer}}:
}
}()

var srvDetails *hvSockDetails
select {
//case <-ctx.Done():
// return ctx.Err()
case r := <-chsrv:
// if r.err != nil {
// return r.err
// }
srvDetails = r.srvDetails
}

srvDetails.startRecvAndSendLoop()

/*
hvsockAddr := &winio.HvsockAddr{
VMID: gcs.HV_GUID_LOOPBACK, // HV_GUID_PARENT
ServiceID: WindowsSidecarGcsHvsockServiceID,
}
hcsockDialer := &winio.HvsockDialer{
Deadline: time.Now().Add(10 * time.Minute),
Retries: 1000,
RetryWait: time.Second,
}
hv := hvSockDetails{hvsockAddr: hvsockAddr, hvsockDialer: hcsockDialer}
hv.startRecvAndSendLoop()
*/
}
86 changes: 86 additions & 0 deletions cmd/gcs-test-server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package main

import (
"fmt"
"log"
"net"
"os"
"strings"

"github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/gcs"
)

var WindowsSidecarGcsHvsockServiceID = guid.GUID{
Data1: 0xae8da506,
Data2: 0xa019,
Data3: 0x4553,
Data4: [8]uint8{0xa5, 0x2b, 0x90, 0x2b, 0xc0, 0xfa, 0x04, 0x11},
}

func handleRequest(conn net.Conn) {
for {
buffer := make([]byte, 1024)

// use bufio.Scanner
length, err := conn.Read(buffer)
if err != nil {
//log.Panicln(err)
errString := fmt.Sprintf("%s", err)
if !strings.Contains(errString, "EOF") {
log.Printf("error reading %s", err)
} else {
continue
}
}

str := string(buffer[:length])
log.Printf("Received command %d\t:%s\n", length, str)

strreply := fmt.Sprintf("I got %s", str)
conn.Write([]byte(strreply + "\n"))

}
}

func main() {
f, err := os.OpenFile("C:/service-debug-gcs-sidecar-server.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalln(fmt.Errorf("error opening file: %v", err))
}
defer f.Close()

log.SetOutput(f)

hvsockAddr := &winio.HvsockAddr{
VMID: gcs.HV_GUID_LOOPBACK,
ServiceID: WindowsSidecarGcsHvsockServiceID,
}

listener, err := winio.ListenHvsock(hvsockAddr)
if err != nil {
//return err
fmt.Printf("!! err listening to sock add with err %v", err)
return
}

fmt.Printf("! Listeing to server at %v", hvsockAddr)

log.Printf("! Listeing to server at %v", hvsockAddr)
var sidecarGcsListener net.Listener
sidecarGcsListener = listener

var conn net.Conn

for {
//conn, err = listener.Accept()
conn, err = sidecarGcsListener.Accept()
if err != nil {
log.Printf("Err accepting connection %v", err)
}
log.Printf("got a new connection con: %v", conn)
go handleRequest(conn)
}

}
Binary file added gcs-sidecar.exe~
Binary file not shown.
8 changes: 8 additions & 0 deletions internal/gcs/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ var HV_GUID_PARENT = guid.GUID{
Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78},
}

// e0e16197-dd56-4a10-9195-5ee7a155a838
var HV_GUID_LOOPBACK = guid.GUID{
Data1: 0xe0e16197,
Data2: 0xdd56,
Data3: 0x4a10,
Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38},
}

// WindowsGcsHvHostID is the hvsock address for the parent of the VM running the GCS
var WindowsGcsHvHostID = guid.GUID{
Data1: 0x894cc2d6,
Expand Down

0 comments on commit 131ff98

Please sign in to comment.