Files
go_pwner/pipe_windows_test.go
T
2026-07-18 21:37:15 +03:00

85 lines
1.9 KiB
Go

//go:build windows
package winpwn
import (
"fmt"
"testing"
"time"
)
// TestNamedPipeServerClient exercises ServePipe/DialPipe end to end: a
// goroutine plays the server (CreateNamedPipe + ConnectNamedPipe, both
// overlapped), the test goroutine plays the client (CreateFile), and both
// sides talk over the resulting *Tube exactly like any other transport.
func TestNamedPipeServerClient(t *testing.T) {
pipeName := fmt.Sprintf("winpwn_test_%d", time.Now().UnixNano())
serverErr := make(chan error, 1)
serverMsg := make(chan []byte, 1)
go func() {
tube, err := ServePipe(pipeName)
if err != nil {
serverErr <- err
return
}
defer tube.Close()
got, err := tube.RecvLine()
if err != nil {
serverErr <- err
return
}
serverMsg <- got
if err := tube.SendLine([]byte("pong")); err != nil {
serverErr <- err
return
}
serverErr <- nil
}()
// ServePipe's CreateNamedPipe call may not have run yet; retry the
// dial briefly rather than racing it with a fixed sleep.
var client *Tube
var err error
for i := 0; i < 100; i++ {
client, err = DialPipe(pipeName)
if err == nil {
break
}
time.Sleep(20 * time.Millisecond)
}
if err != nil {
t.Fatalf("DialPipe: %v", err)
}
defer client.Close()
if err := client.SendLine([]byte("ping")); err != nil {
t.Fatalf("client SendLine: %v", err)
}
select {
case got := <-serverMsg:
if string(got) != "ping\n" {
t.Errorf("server received %q, want %q", got, "ping\n")
}
case err := <-serverErr:
t.Fatalf("server error: %v", err)
case <-time.After(5 * time.Second):
t.Fatal("timed out waiting for the server to receive the client's message")
}
got, err := client.RecvLine()
if err != nil {
t.Fatalf("client RecvLine: %v", err)
}
if string(got) != "pong\n" {
t.Errorf("client received %q, want %q", got, "pong\n")
}
if err := <-serverErr; err != nil {
t.Fatalf("server goroutine error: %v", err)
}
}