Browse code

Revendor go-winio

This is needed to provide fixes for ETW on ARM. The updated ETW package will
no-op on ARM, rather than crashing. Further changes are needed to Go itself to
allow ETW on ARM to work properly.

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>
(cherry picked from commit e1f0f77bf49ca0fab29eb57ce25ac3f6eab0adf9)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Kevin Parsons authored on 2019/04/23 06:11:46
Showing 18 changed files
... ...
@@ -1,6 +1,6 @@
1 1
 github.com/Azure/go-ansiterm                        d6e3b3328b783f23731bc4d058875b0371ff8109
2 2
 github.com/Microsoft/hcsshim                        672e52e9209d1e53718c1b6a7d68cc9272654ab5
3
-github.com/Microsoft/go-winio                       c599b533b43b1363d7d7c6cfda5ede70ed73ff13
3
+github.com/Microsoft/go-winio                       3fe4fa31662f6ede2353d913e93907b8e096e0b6
4 4
 github.com/docker/libtrust                          9cbd2a1374f46905c68a4eb3694a130610adc62a
5 5
 github.com/go-check/check                           4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
6 6
 github.com/golang/gddo                              9b12a26f3fbd7397dee4e20939ddca719d840d2a
... ...
@@ -16,6 +16,7 @@ import (
16 16
 //sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
17 17
 //sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
18 18
 //sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
19
+//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
19 20
 
20 21
 type atomicBool int32
21 22
 
... ...
@@ -79,6 +80,7 @@ type win32File struct {
79 79
 	wg            sync.WaitGroup
80 80
 	wgLock        sync.RWMutex
81 81
 	closing       atomicBool
82
+	socket        bool
82 83
 	readDeadline  deadlineHandler
83 84
 	writeDeadline deadlineHandler
84 85
 }
... ...
@@ -190,6 +192,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
190 190
 			if f.closing.isSet() {
191 191
 				err = ErrFileClosed
192 192
 			}
193
+		} else if err != nil && f.socket {
194
+			// err is from Win32. Query the overlapped structure to get the winsock error.
195
+			var bytes, flags uint32
196
+			err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
193 197
 		}
194 198
 	case <-timeout:
195 199
 		cancelIoEx(f.handle, &c.o)
196 200
new file mode 100644
... ...
@@ -0,0 +1,305 @@
0
+package winio
1
+
2
+import (
3
+	"fmt"
4
+	"io"
5
+	"net"
6
+	"os"
7
+	"syscall"
8
+	"time"
9
+	"unsafe"
10
+
11
+	"github.com/Microsoft/go-winio/pkg/guid"
12
+)
13
+
14
+//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
15
+
16
+const (
17
+	afHvSock = 34 // AF_HYPERV
18
+
19
+	socketError = ^uintptr(0)
20
+)
21
+
22
+// An HvsockAddr is an address for a AF_HYPERV socket.
23
+type HvsockAddr struct {
24
+	VMID      guid.GUID
25
+	ServiceID guid.GUID
26
+}
27
+
28
+type rawHvsockAddr struct {
29
+	Family    uint16
30
+	_         uint16
31
+	VMID      guid.GUID
32
+	ServiceID guid.GUID
33
+}
34
+
35
+// Network returns the address's network name, "hvsock".
36
+func (addr *HvsockAddr) Network() string {
37
+	return "hvsock"
38
+}
39
+
40
+func (addr *HvsockAddr) String() string {
41
+	return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
42
+}
43
+
44
+// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
45
+func VsockServiceID(port uint32) guid.GUID {
46
+	g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
47
+	g.Data1 = port
48
+	return *g
49
+}
50
+
51
+func (addr *HvsockAddr) raw() rawHvsockAddr {
52
+	return rawHvsockAddr{
53
+		Family:    afHvSock,
54
+		VMID:      addr.VMID,
55
+		ServiceID: addr.ServiceID,
56
+	}
57
+}
58
+
59
+func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
60
+	addr.VMID = raw.VMID
61
+	addr.ServiceID = raw.ServiceID
62
+}
63
+
64
+// HvsockListener is a socket listener for the AF_HYPERV address family.
65
+type HvsockListener struct {
66
+	sock *win32File
67
+	addr HvsockAddr
68
+}
69
+
70
+// HvsockConn is a connected socket of the AF_HYPERV address family.
71
+type HvsockConn struct {
72
+	sock          *win32File
73
+	local, remote HvsockAddr
74
+}
75
+
76
+func newHvSocket() (*win32File, error) {
77
+	fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
78
+	if err != nil {
79
+		return nil, os.NewSyscallError("socket", err)
80
+	}
81
+	f, err := makeWin32File(fd)
82
+	if err != nil {
83
+		syscall.Close(fd)
84
+		return nil, err
85
+	}
86
+	f.socket = true
87
+	return f, nil
88
+}
89
+
90
+// ListenHvsock listens for connections on the specified hvsock address.
91
+func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
92
+	l := &HvsockListener{addr: *addr}
93
+	sock, err := newHvSocket()
94
+	if err != nil {
95
+		return nil, l.opErr("listen", err)
96
+	}
97
+	sa := addr.raw()
98
+	err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
99
+	if err != nil {
100
+		return nil, l.opErr("listen", os.NewSyscallError("socket", err))
101
+	}
102
+	err = syscall.Listen(sock.handle, 16)
103
+	if err != nil {
104
+		return nil, l.opErr("listen", os.NewSyscallError("listen", err))
105
+	}
106
+	return &HvsockListener{sock: sock, addr: *addr}, nil
107
+}
108
+
109
+func (l *HvsockListener) opErr(op string, err error) error {
110
+	return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
111
+}
112
+
113
+// Addr returns the listener's network address.
114
+func (l *HvsockListener) Addr() net.Addr {
115
+	return &l.addr
116
+}
117
+
118
+// Accept waits for the next connection and returns it.
119
+func (l *HvsockListener) Accept() (_ net.Conn, err error) {
120
+	sock, err := newHvSocket()
121
+	if err != nil {
122
+		return nil, l.opErr("accept", err)
123
+	}
124
+	defer func() {
125
+		if sock != nil {
126
+			sock.Close()
127
+		}
128
+	}()
129
+	c, err := l.sock.prepareIo()
130
+	if err != nil {
131
+		return nil, l.opErr("accept", err)
132
+	}
133
+	defer l.sock.wg.Done()
134
+
135
+	// AcceptEx, per documentation, requires an extra 16 bytes per address.
136
+	const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
137
+	var addrbuf [addrlen * 2]byte
138
+
139
+	var bytes uint32
140
+	err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
141
+	_, err = l.sock.asyncIo(c, nil, bytes, err)
142
+	if err != nil {
143
+		return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
144
+	}
145
+	conn := &HvsockConn{
146
+		sock: sock,
147
+	}
148
+	conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
149
+	conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
150
+	sock = nil
151
+	return conn, nil
152
+}
153
+
154
+// Close closes the listener, causing any pending Accept calls to fail.
155
+func (l *HvsockListener) Close() error {
156
+	return l.sock.Close()
157
+}
158
+
159
+/* Need to finish ConnectEx handling
160
+func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
161
+	sock, err := newHvSocket()
162
+	if err != nil {
163
+		return nil, err
164
+	}
165
+	defer func() {
166
+		if sock != nil {
167
+			sock.Close()
168
+		}
169
+	}()
170
+	c, err := sock.prepareIo()
171
+	if err != nil {
172
+		return nil, err
173
+	}
174
+	defer sock.wg.Done()
175
+	var bytes uint32
176
+	err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
177
+	_, err = sock.asyncIo(ctx, c, nil, bytes, err)
178
+	if err != nil {
179
+		return nil, err
180
+	}
181
+	conn := &HvsockConn{
182
+		sock:   sock,
183
+		remote: *addr,
184
+	}
185
+	sock = nil
186
+	return conn, nil
187
+}
188
+*/
189
+
190
+func (conn *HvsockConn) opErr(op string, err error) error {
191
+	return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
192
+}
193
+
194
+func (conn *HvsockConn) Read(b []byte) (int, error) {
195
+	c, err := conn.sock.prepareIo()
196
+	if err != nil {
197
+		return 0, conn.opErr("read", err)
198
+	}
199
+	defer conn.sock.wg.Done()
200
+	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
201
+	var flags, bytes uint32
202
+	err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
203
+	n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
204
+	if err != nil {
205
+		if _, ok := err.(syscall.Errno); ok {
206
+			err = os.NewSyscallError("wsarecv", err)
207
+		}
208
+		return 0, conn.opErr("read", err)
209
+	} else if n == 0 {
210
+		err = io.EOF
211
+	}
212
+	return n, err
213
+}
214
+
215
+func (conn *HvsockConn) Write(b []byte) (int, error) {
216
+	t := 0
217
+	for len(b) != 0 {
218
+		n, err := conn.write(b)
219
+		if err != nil {
220
+			return t + n, err
221
+		}
222
+		t += n
223
+		b = b[n:]
224
+	}
225
+	return t, nil
226
+}
227
+
228
+func (conn *HvsockConn) write(b []byte) (int, error) {
229
+	c, err := conn.sock.prepareIo()
230
+	if err != nil {
231
+		return 0, conn.opErr("write", err)
232
+	}
233
+	defer conn.sock.wg.Done()
234
+	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
235
+	var bytes uint32
236
+	err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
237
+	n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
238
+	if err != nil {
239
+		if _, ok := err.(syscall.Errno); ok {
240
+			err = os.NewSyscallError("wsasend", err)
241
+		}
242
+		return 0, conn.opErr("write", err)
243
+	}
244
+	return n, err
245
+}
246
+
247
+// Close closes the socket connection, failing any pending read or write calls.
248
+func (conn *HvsockConn) Close() error {
249
+	return conn.sock.Close()
250
+}
251
+
252
+func (conn *HvsockConn) shutdown(how int) error {
253
+	err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
254
+	if err != nil {
255
+		return os.NewSyscallError("shutdown", err)
256
+	}
257
+	return nil
258
+}
259
+
260
+// CloseRead shuts down the read end of the socket.
261
+func (conn *HvsockConn) CloseRead() error {
262
+	err := conn.shutdown(syscall.SHUT_RD)
263
+	if err != nil {
264
+		return conn.opErr("close", err)
265
+	}
266
+	return nil
267
+}
268
+
269
+// CloseWrite shuts down the write end of the socket, notifying the other endpoint that
270
+// no more data will be written.
271
+func (conn *HvsockConn) CloseWrite() error {
272
+	err := conn.shutdown(syscall.SHUT_WR)
273
+	if err != nil {
274
+		return conn.opErr("close", err)
275
+	}
276
+	return nil
277
+}
278
+
279
+// LocalAddr returns the local address of the connection.
280
+func (conn *HvsockConn) LocalAddr() net.Addr {
281
+	return &conn.local
282
+}
283
+
284
+// RemoteAddr returns the remote address of the connection.
285
+func (conn *HvsockConn) RemoteAddr() net.Addr {
286
+	return &conn.remote
287
+}
288
+
289
+// SetDeadline implements the net.Conn SetDeadline method.
290
+func (conn *HvsockConn) SetDeadline(t time.Time) error {
291
+	conn.SetReadDeadline(t)
292
+	conn.SetWriteDeadline(t)
293
+	return nil
294
+}
295
+
296
+// SetReadDeadline implements the net.Conn SetReadDeadline method.
297
+func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
298
+	return conn.sock.SetReadDeadline(t)
299
+}
300
+
301
+// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
302
+func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
303
+	return conn.sock.SetWriteDeadline(t)
304
+}
... ...
@@ -3,10 +3,13 @@
3 3
 package winio
4 4
 
5 5
 import (
6
+	"context"
6 7
 	"errors"
8
+	"fmt"
7 9
 	"io"
8 10
 	"net"
9 11
 	"os"
12
+	"runtime"
10 13
 	"syscall"
11 14
 	"time"
12 15
 	"unsafe"
... ...
@@ -18,6 +21,48 @@ import (
18 18
 //sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
19 19
 //sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
20 20
 //sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
21
+//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
22
+//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
23
+//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
24
+//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
25
+
26
+type ioStatusBlock struct {
27
+	Status, Information uintptr
28
+}
29
+
30
+type objectAttributes struct {
31
+	Length             uintptr
32
+	RootDirectory      uintptr
33
+	ObjectName         *unicodeString
34
+	Attributes         uintptr
35
+	SecurityDescriptor *securityDescriptor
36
+	SecurityQoS        uintptr
37
+}
38
+
39
+type unicodeString struct {
40
+	Length        uint16
41
+	MaximumLength uint16
42
+	Buffer        uintptr
43
+}
44
+
45
+type securityDescriptor struct {
46
+	Revision byte
47
+	Sbz1     byte
48
+	Control  uint16
49
+	Owner    uintptr
50
+	Group    uintptr
51
+	Sacl     uintptr
52
+	Dacl     uintptr
53
+}
54
+
55
+type ntstatus int32
56
+
57
+func (status ntstatus) Err() error {
58
+	if status >= 0 {
59
+		return nil
60
+	}
61
+	return rtlNtStatusToDosError(status)
62
+}
21 63
 
22 64
 const (
23 65
 	cERROR_PIPE_BUSY      = syscall.Errno(231)
... ...
@@ -25,21 +70,20 @@ const (
25 25
 	cERROR_PIPE_CONNECTED = syscall.Errno(535)
26 26
 	cERROR_SEM_TIMEOUT    = syscall.Errno(121)
27 27
 
28
-	cPIPE_ACCESS_DUPLEX            = 0x3
29
-	cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
30
-	cSECURITY_SQOS_PRESENT         = 0x100000
31
-	cSECURITY_ANONYMOUS            = 0
28
+	cSECURITY_SQOS_PRESENT = 0x100000
29
+	cSECURITY_ANONYMOUS    = 0
32 30
 
33
-	cPIPE_REJECT_REMOTE_CLIENTS = 0x8
31
+	cPIPE_TYPE_MESSAGE = 4
34 32
 
35
-	cPIPE_UNLIMITED_INSTANCES = 255
33
+	cPIPE_READMODE_MESSAGE = 2
36 34
 
37
-	cNMPWAIT_USE_DEFAULT_WAIT = 0
38
-	cNMPWAIT_NOWAIT           = 1
35
+	cFILE_OPEN   = 1
36
+	cFILE_CREATE = 2
39 37
 
40
-	cPIPE_TYPE_MESSAGE = 4
38
+	cFILE_PIPE_MESSAGE_TYPE          = 1
39
+	cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
41 40
 
42
-	cPIPE_READMODE_MESSAGE = 2
41
+	cSE_DACL_PRESENT = 4
43 42
 )
44 43
 
45 44
 var (
... ...
@@ -137,9 +181,30 @@ func (s pipeAddress) String() string {
137 137
 	return string(s)
138 138
 }
139 139
 
140
+// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
141
+func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) {
142
+	for {
143
+		select {
144
+		case <-ctx.Done():
145
+			return syscall.Handle(0), ctx.Err()
146
+		default:
147
+			h, err := createFile(*path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
148
+			if err == nil {
149
+				return h, nil
150
+			}
151
+			if err != cERROR_PIPE_BUSY {
152
+				return h, &os.PathError{Err: err, Op: "open", Path: *path}
153
+			}
154
+			// Wait 10 msec and try again. This is a rather simplistic
155
+			// view, as we always try each 10 milliseconds.
156
+			time.Sleep(time.Millisecond * 10)
157
+		}
158
+	}
159
+}
160
+
140 161
 // DialPipe connects to a named pipe by path, timing out if the connection
141 162
 // takes longer than the specified duration. If timeout is nil, then we use
142
-// a default timeout of 5 seconds.  (We do not use WaitNamedPipe.)
163
+// a default timeout of 2 seconds.  (We do not use WaitNamedPipe.)
143 164
 func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
144 165
 	var absTimeout time.Time
145 166
 	if timeout != nil {
... ...
@@ -147,23 +212,22 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
147 147
 	} else {
148 148
 		absTimeout = time.Now().Add(time.Second * 2)
149 149
 	}
150
+	ctx, _ := context.WithDeadline(context.Background(), absTimeout)
151
+	conn, err := DialPipeContext(ctx, path)
152
+	if err == context.DeadlineExceeded {
153
+		return nil, ErrTimeout
154
+	}
155
+	return conn, err
156
+}
157
+
158
+// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
159
+// cancellation or timeout.
160
+func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
150 161
 	var err error
151 162
 	var h syscall.Handle
152
-	for {
153
-		h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
154
-		if err != cERROR_PIPE_BUSY {
155
-			break
156
-		}
157
-		if time.Now().After(absTimeout) {
158
-			return nil, ErrTimeout
159
-		}
160
-
161
-		// Wait 10 msec and try again. This is a rather simplistic
162
-		// view, as we always try each 10 milliseconds.
163
-		time.Sleep(time.Millisecond * 10)
164
-	}
163
+	h, err = tryDialPipe(ctx, &path)
165 164
 	if err != nil {
166
-		return nil, &os.PathError{Op: "open", Path: path, Err: err}
165
+		return nil, err
167 166
 	}
168 167
 
169 168
 	var flags uint32
... ...
@@ -194,43 +258,87 @@ type acceptResponse struct {
194 194
 }
195 195
 
196 196
 type win32PipeListener struct {
197
-	firstHandle        syscall.Handle
198
-	path               string
199
-	securityDescriptor []byte
200
-	config             PipeConfig
201
-	acceptCh           chan (chan acceptResponse)
202
-	closeCh            chan int
203
-	doneCh             chan int
197
+	firstHandle syscall.Handle
198
+	path        string
199
+	config      PipeConfig
200
+	acceptCh    chan (chan acceptResponse)
201
+	closeCh     chan int
202
+	doneCh      chan int
204 203
 }
205 204
 
206
-func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
207
-	var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
205
+func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
206
+	path16, err := syscall.UTF16FromString(path)
207
+	if err != nil {
208
+		return 0, &os.PathError{Op: "open", Path: path, Err: err}
209
+	}
210
+
211
+	var oa objectAttributes
212
+	oa.Length = unsafe.Sizeof(oa)
213
+
214
+	var ntPath unicodeString
215
+	if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
216
+		return 0, &os.PathError{Op: "open", Path: path, Err: err}
217
+	}
218
+	defer localFree(ntPath.Buffer)
219
+	oa.ObjectName = &ntPath
220
+
221
+	// The security descriptor is only needed for the first pipe.
208 222
 	if first {
209
-		flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
223
+		if sd != nil {
224
+			len := uint32(len(sd))
225
+			sdb := localAlloc(0, len)
226
+			defer localFree(sdb)
227
+			copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
228
+			oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
229
+		} else {
230
+			// Construct the default named pipe security descriptor.
231
+			var dacl uintptr
232
+			if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
233
+				return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
234
+			}
235
+			defer localFree(dacl)
236
+
237
+			sdb := &securityDescriptor{
238
+				Revision: 1,
239
+				Control:  cSE_DACL_PRESENT,
240
+				Dacl:     dacl,
241
+			}
242
+			oa.SecurityDescriptor = sdb
243
+		}
210 244
 	}
211 245
 
212
-	var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS
246
+	typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
213 247
 	if c.MessageMode {
214
-		mode |= cPIPE_TYPE_MESSAGE
248
+		typ |= cFILE_PIPE_MESSAGE_TYPE
215 249
 	}
216 250
 
217
-	sa := &syscall.SecurityAttributes{}
218
-	sa.Length = uint32(unsafe.Sizeof(*sa))
219
-	if securityDescriptor != nil {
220
-		len := uint32(len(securityDescriptor))
221
-		sa.SecurityDescriptor = localAlloc(0, len)
222
-		defer localFree(sa.SecurityDescriptor)
223
-		copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor)
251
+	disposition := uint32(cFILE_OPEN)
252
+	access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
253
+	if first {
254
+		disposition = cFILE_CREATE
255
+		// By not asking for read or write access, the named pipe file system
256
+		// will put this pipe into an initially disconnected state, blocking
257
+		// client connections until the next call with first == false.
258
+		access = syscall.SYNCHRONIZE
224 259
 	}
225
-	h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa)
260
+
261
+	timeout := int64(-50 * 10000) // 50ms
262
+
263
+	var (
264
+		h    syscall.Handle
265
+		iosb ioStatusBlock
266
+	)
267
+	err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
226 268
 	if err != nil {
227 269
 		return 0, &os.PathError{Op: "open", Path: path, Err: err}
228 270
 	}
271
+
272
+	runtime.KeepAlive(ntPath)
229 273
 	return h, nil
230 274
 }
231 275
 
232 276
 func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
233
-	h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
277
+	h, err := makeServerPipeHandle(l.path, nil, &l.config, false)
234 278
 	if err != nil {
235 279
 		return nil, err
236 280
 	}
... ...
@@ -341,32 +449,13 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
341 341
 	if err != nil {
342 342
 		return nil, err
343 343
 	}
344
-	// Create a client handle and connect it.  This results in the pipe
345
-	// instance always existing, so that clients see ERROR_PIPE_BUSY
346
-	// rather than ERROR_FILE_NOT_FOUND.  This ties the first instance
347
-	// up so that no other instances can be used.  This would have been
348
-	// cleaner if the Win32 API matched CreateFile with ConnectNamedPipe
349
-	// instead of CreateNamedPipe.  (Apparently created named pipes are
350
-	// considered to be in listening state regardless of whether any
351
-	// active calls to ConnectNamedPipe are outstanding.)
352
-	h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
353
-	if err != nil {
354
-		syscall.Close(h)
355
-		return nil, err
356
-	}
357
-	// Close the client handle. The server side of the instance will
358
-	// still be busy, leading to ERROR_PIPE_BUSY instead of
359
-	// ERROR_NOT_FOUND, as long as we don't close the server handle,
360
-	// or disconnect the client with DisconnectNamedPipe.
361
-	syscall.Close(h2)
362 344
 	l := &win32PipeListener{
363
-		firstHandle:        h,
364
-		path:               path,
365
-		securityDescriptor: sd,
366
-		config:             *c,
367
-		acceptCh:           make(chan (chan acceptResponse)),
368
-		closeCh:            make(chan int),
369
-		doneCh:             make(chan int),
345
+		firstHandle: h,
346
+		path:        path,
347
+		config:      *c,
348
+		acceptCh:    make(chan (chan acceptResponse)),
349
+		closeCh:     make(chan int),
350
+		doneCh:      make(chan int),
370 351
 	}
371 352
 	go l.listenerRoutine()
372 353
 	return l, nil
... ...
@@ -7,9 +7,14 @@
7 7
 // set of C macros.
8 8
 package etw
9 9
 
10
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go
10
+//go:generate go run mksyscall_windows.go -output zsyscall_windows.go etw.go
11 11
 
12 12
 //sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
13
-//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
14
-//sys eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
15
-//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
13
+
14
+//sys eventUnregister_64(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
15
+//sys eventWriteTransfer_64(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
16
+//sys eventSetInformation_64(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
17
+
18
+//sys eventUnregister_32(providerHandle_low uint32, providerHandle_high uint32) (win32err error) = advapi32.EventUnregister
19
+//sys eventWriteTransfer_32(providerHandle_low uint32, providerHandle_high uint32, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
20
+//sys eventSetInformation_32(providerHandle_low uint32, providerHandle_high uint32, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
... ...
@@ -17,7 +17,7 @@ const (
17 17
 // will always be collected.
18 18
 type Level uint8
19 19
 
20
-// Predefined ETW log levels.
20
+// Predefined ETW log levels from winmeta.xml in the Windows SDK.
21 21
 const (
22 22
 	LevelAlways Level = iota
23 23
 	LevelCritical
... ...
@@ -27,13 +27,30 @@ const (
27 27
 	LevelVerbose
28 28
 )
29 29
 
30
+// Opcode represents the operation that the event indicates is being performed.
31
+type Opcode uint8
32
+
33
+// Predefined ETW opcodes from winmeta.xml in the Windows SDK.
34
+const (
35
+	// OpcodeInfo indicates an informational event.
36
+	OpcodeInfo Opcode = iota
37
+	// OpcodeStart indicates the start of an operation.
38
+	OpcodeStart
39
+	// OpcodeStop indicates the end of an operation.
40
+	OpcodeStop
41
+	// OpcodeDCStart indicates the start of a provider capture state operation.
42
+	OpcodeDCStart
43
+	// OpcodeDCStop indicates the end of a provider capture state operation.
44
+	OpcodeDCStop
45
+)
46
+
30 47
 // EventDescriptor represents various metadata for an ETW event.
31 48
 type eventDescriptor struct {
32 49
 	id      uint16
33 50
 	version uint8
34 51
 	channel Channel
35 52
 	level   Level
36
-	opcode  uint8
53
+	opcode  Opcode
37 54
 	task    uint16
38 55
 	keyword uint64
39 56
 }
... ...
@@ -1,13 +1,13 @@
1 1
 package etw
2 2
 
3 3
 import (
4
-	"golang.org/x/sys/windows"
4
+	"github.com/Microsoft/go-winio/pkg/guid"
5 5
 )
6 6
 
7 7
 type eventOptions struct {
8 8
 	descriptor        *eventDescriptor
9
-	activityID        *windows.GUID
10
-	relatedActivityID *windows.GUID
9
+	activityID        *guid.GUID
10
+	relatedActivityID *guid.GUID
11 11
 	tags              uint32
12 12
 }
13 13
 
... ...
@@ -36,12 +36,20 @@ func WithKeyword(keyword uint64) EventOpt {
36 36
 	}
37 37
 }
38 38
 
39
+// WithChannel specifies the channel of the event to be written.
39 40
 func WithChannel(channel Channel) EventOpt {
40 41
 	return func(options *eventOptions) {
41 42
 		options.descriptor.channel = channel
42 43
 	}
43 44
 }
44 45
 
46
+// WithOpcode specifies the opcode of the event to be written.
47
+func WithOpcode(opcode Opcode) EventOpt {
48
+	return func(options *eventOptions) {
49
+		options.descriptor.opcode = opcode
50
+	}
51
+}
52
+
45 53
 // WithTags specifies the tags of the event to be written. Tags is a 28-bit
46 54
 // value (top 4 bits are ignored) which are interpreted by the event consumer.
47 55
 func WithTags(newTags uint32) EventOpt {
... ...
@@ -50,13 +58,15 @@ func WithTags(newTags uint32) EventOpt {
50 50
 	}
51 51
 }
52 52
 
53
-func WithActivityID(activityID *windows.GUID) EventOpt {
53
+// WithActivityID specifies the activity ID of the event to be written.
54
+func WithActivityID(activityID *guid.GUID) EventOpt {
54 55
 	return func(options *eventOptions) {
55 56
 		options.activityID = activityID
56 57
 	}
57 58
 }
58 59
 
59
-func WithRelatedActivityID(activityID *windows.GUID) EventOpt {
60
+// WithRelatedActivityID specifies the parent activity ID of the event to be written.
61
+func WithRelatedActivityID(activityID *guid.GUID) EventOpt {
60 62
 	return func(options *eventOptions) {
61 63
 		options.relatedActivityID = activityID
62 64
 	}
... ...
@@ -1,7 +1,9 @@
1 1
 package etw
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"math"
6
+	"reflect"
5 7
 	"unsafe"
6 8
 )
7 9
 
... ...
@@ -377,3 +379,124 @@ func Struct(name string, opts ...FieldOpt) FieldOpt {
377 377
 		}
378 378
 	}
379 379
 }
380
+
381
+// Currently, we support logging basic builtin types (int, string, etc), slices
382
+// of basic builtin types, error, types derived from the basic types (e.g. "type
383
+// foo int"), and structs (recursively logging their fields). We do not support
384
+// slices of derived types (e.g. "[]foo").
385
+//
386
+// For types that we don't support, the value is formatted via fmt.Sprint, and
387
+// we also log a message that the type is unsupported along with the formatted
388
+// type. The intent of this is to make it easier to see which types are not
389
+// supported in traces, so we can evaluate adding support for more types in the
390
+// future.
391
+func SmartField(name string, v interface{}) FieldOpt {
392
+	switch v := v.(type) {
393
+	case bool:
394
+		return BoolField(name, v)
395
+	case []bool:
396
+		return BoolArray(name, v)
397
+	case string:
398
+		return StringField(name, v)
399
+	case []string:
400
+		return StringArray(name, v)
401
+	case int:
402
+		return IntField(name, v)
403
+	case []int:
404
+		return IntArray(name, v)
405
+	case int8:
406
+		return Int8Field(name, v)
407
+	case []int8:
408
+		return Int8Array(name, v)
409
+	case int16:
410
+		return Int16Field(name, v)
411
+	case []int16:
412
+		return Int16Array(name, v)
413
+	case int32:
414
+		return Int32Field(name, v)
415
+	case []int32:
416
+		return Int32Array(name, v)
417
+	case int64:
418
+		return Int64Field(name, v)
419
+	case []int64:
420
+		return Int64Array(name, v)
421
+	case uint:
422
+		return UintField(name, v)
423
+	case []uint:
424
+		return UintArray(name, v)
425
+	case uint8:
426
+		return Uint8Field(name, v)
427
+	case []uint8:
428
+		return Uint8Array(name, v)
429
+	case uint16:
430
+		return Uint16Field(name, v)
431
+	case []uint16:
432
+		return Uint16Array(name, v)
433
+	case uint32:
434
+		return Uint32Field(name, v)
435
+	case []uint32:
436
+		return Uint32Array(name, v)
437
+	case uint64:
438
+		return Uint64Field(name, v)
439
+	case []uint64:
440
+		return Uint64Array(name, v)
441
+	case uintptr:
442
+		return UintptrField(name, v)
443
+	case []uintptr:
444
+		return UintptrArray(name, v)
445
+	case float32:
446
+		return Float32Field(name, v)
447
+	case []float32:
448
+		return Float32Array(name, v)
449
+	case float64:
450
+		return Float64Field(name, v)
451
+	case []float64:
452
+		return Float64Array(name, v)
453
+	case error:
454
+		return StringField(name, v.Error())
455
+	default:
456
+		switch rv := reflect.ValueOf(v); rv.Kind() {
457
+		case reflect.Bool:
458
+			return SmartField(name, rv.Bool())
459
+		case reflect.Int:
460
+			return SmartField(name, int(rv.Int()))
461
+		case reflect.Int8:
462
+			return SmartField(name, int8(rv.Int()))
463
+		case reflect.Int16:
464
+			return SmartField(name, int16(rv.Int()))
465
+		case reflect.Int32:
466
+			return SmartField(name, int32(rv.Int()))
467
+		case reflect.Int64:
468
+			return SmartField(name, int64(rv.Int()))
469
+		case reflect.Uint:
470
+			return SmartField(name, uint(rv.Uint()))
471
+		case reflect.Uint8:
472
+			return SmartField(name, uint8(rv.Uint()))
473
+		case reflect.Uint16:
474
+			return SmartField(name, uint16(rv.Uint()))
475
+		case reflect.Uint32:
476
+			return SmartField(name, uint32(rv.Uint()))
477
+		case reflect.Uint64:
478
+			return SmartField(name, uint64(rv.Uint()))
479
+		case reflect.Uintptr:
480
+			return SmartField(name, uintptr(rv.Uint()))
481
+		case reflect.Float32:
482
+			return SmartField(name, float32(rv.Float()))
483
+		case reflect.Float64:
484
+			return SmartField(name, float64(rv.Float()))
485
+		case reflect.String:
486
+			return SmartField(name, rv.String())
487
+		case reflect.Struct:
488
+			fields := make([]FieldOpt, 0, rv.NumField())
489
+			for i := 0; i < rv.NumField(); i++ {
490
+				field := rv.Field(i)
491
+				if field.CanInterface() {
492
+					fields = append(fields, SmartField(name, field.Interface()))
493
+				}
494
+			}
495
+			return Struct(name, fields...)
496
+		}
497
+	}
498
+
499
+	return StringField(name, fmt.Sprintf("(Unsupported: %T) %v", v, v))
500
+}
380 501
new file mode 100644
... ...
@@ -0,0 +1,53 @@
0
+// +build amd64 arm64 386
1
+
2
+package etw
3
+
4
+import (
5
+	"bytes"
6
+	"encoding/binary"
7
+	"unsafe"
8
+
9
+	"github.com/Microsoft/go-winio/pkg/guid"
10
+	"golang.org/x/sys/windows"
11
+)
12
+
13
+// NewProviderWithID creates and registers a new ETW provider, allowing the
14
+// provider ID to be manually specified. This is most useful when there is an
15
+// existing provider ID that must be used to conform to existing diagnostic
16
+// infrastructure.
17
+func NewProviderWithID(name string, id *guid.GUID, callback EnableCallback) (provider *Provider, err error) {
18
+	providerCallbackOnce.Do(func() {
19
+		globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
20
+	})
21
+
22
+	provider = providers.newProvider()
23
+	defer func(provider *Provider) {
24
+		if err != nil {
25
+			providers.removeProvider(provider)
26
+		}
27
+	}(provider)
28
+	provider.ID = id
29
+	provider.callback = callback
30
+
31
+	if err := eventRegister((*windows.GUID)(provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
32
+		return nil, err
33
+	}
34
+
35
+	metadata := &bytes.Buffer{}
36
+	binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
37
+	metadata.WriteString(name)
38
+	metadata.WriteByte(0)                                                   // Null terminator for name
39
+	binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
40
+	provider.metadata = metadata.Bytes()
41
+
42
+	if err := eventSetInformation(
43
+		provider.handle,
44
+		eventInfoClassProviderSetTraits,
45
+		uintptr(unsafe.Pointer(&provider.metadata[0])),
46
+		uint32(len(provider.metadata))); err != nil {
47
+
48
+		return nil, err
49
+	}
50
+
51
+	return provider, nil
52
+}
0 53
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+// +build arm
1
+
2
+package etw
3
+
4
+import (
5
+	"github.com/Microsoft/go-winio/pkg/guid"
6
+)
7
+
8
+// NewProviderWithID returns a nil provider on unsupported platforms.
9
+func NewProviderWithID(name string, id *guid.GUID, callback EnableCallback) (provider *Provider, err error) {
10
+	return nil, nil
11
+}
... ...
@@ -1,15 +1,12 @@
1 1
 package etw
2 2
 
3 3
 import (
4
-	"bytes"
5 4
 	"crypto/sha1"
6 5
 	"encoding/binary"
7
-	"encoding/hex"
8
-	"fmt"
9 6
 	"strings"
10 7
 	"unicode/utf16"
11
-	"unsafe"
12 8
 
9
+	"github.com/Microsoft/go-winio/pkg/guid"
13 10
 	"golang.org/x/sys/windows"
14 11
 )
15 12
 
... ...
@@ -17,7 +14,7 @@ import (
17 17
 // name and ID (GUID), which should always have a 1:1 mapping to each other
18 18
 // (e.g. don't use multiple provider names with the same ID, or vice versa).
19 19
 type Provider struct {
20
-	ID         *windows.GUID
20
+	ID         *guid.GUID
21 21
 	handle     providerHandle
22 22
 	metadata   []byte
23 23
 	callback   EnableCallback
... ...
@@ -30,22 +27,14 @@ type Provider struct {
30 30
 
31 31
 // String returns the `provider`.ID as a string
32 32
 func (provider *Provider) String() string {
33
-	data1 := make([]byte, 4)
34
-	binary.BigEndian.PutUint32(data1, provider.ID.Data1)
35
-	data2 := make([]byte, 2)
36
-	binary.BigEndian.PutUint16(data2, provider.ID.Data2)
37
-	data3 := make([]byte, 2)
38
-	binary.BigEndian.PutUint16(data3, provider.ID.Data3)
39
-	return fmt.Sprintf(
40
-		"%s-%s-%s-%s-%s",
41
-		hex.EncodeToString(data1),
42
-		hex.EncodeToString(data2),
43
-		hex.EncodeToString(data3),
44
-		hex.EncodeToString(provider.ID.Data4[:2]),
45
-		hex.EncodeToString(provider.ID.Data4[2:]))
33
+	if provider == nil {
34
+		return "<nil>"
35
+	}
36
+
37
+	return provider.ID.String()
46 38
 }
47 39
 
48
-type providerHandle windows.Handle
40
+type providerHandle uint64
49 41
 
50 42
 // ProviderState informs the provider EnableCallback what action is being
51 43
 // performed.
... ...
@@ -72,9 +61,9 @@ const (
72 72
 
73 73
 // EnableCallback is the form of the callback function that receives provider
74 74
 // enable/disable notifications from ETW.
75
-type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr)
75
+type EnableCallback func(*guid.GUID, ProviderState, Level, uint64, uint64, uintptr)
76 76
 
77
-func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
77
+func providerCallback(sourceID *guid.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
78 78
 	provider := providers.getProvider(uint(i))
79 79
 
80 80
 	switch state {
... ...
@@ -96,7 +85,7 @@ func providerCallback(sourceID *windows.GUID, state ProviderState, level Level,
96 96
 // for provider notifications. Because Go has trouble with callback arguments of
97 97
 // different size, it has only pointer-sized arguments, which are then cast to
98 98
 // the appropriate types when calling providerCallback.
99
-func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
99
+func providerCallbackAdapter(sourceID *guid.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
100 100
 	providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
101 101
 	return 0
102 102
 }
... ...
@@ -108,7 +97,7 @@ func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintpt
108 108
 // The algorithm is roughly:
109 109
 // Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
110 110
 // Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
111
-func providerIDFromName(name string) *windows.GUID {
111
+func providerIDFromName(name string) *guid.GUID {
112 112
 	buffer := sha1.New()
113 113
 
114 114
 	namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
... ...
@@ -119,7 +108,7 @@ func providerIDFromName(name string) *windows.GUID {
119 119
 	sum := buffer.Sum(nil)
120 120
 	sum[7] = (sum[7] & 0xf) | 0x50
121 121
 
122
-	return &windows.GUID{
122
+	return &guid.GUID{
123 123
 		Data1: binary.LittleEndian.Uint32(sum[0:4]),
124 124
 		Data2: binary.LittleEndian.Uint16(sum[4:6]),
125 125
 		Data3: binary.LittleEndian.Uint16(sum[6:8]),
... ...
@@ -133,49 +122,12 @@ func NewProvider(name string, callback EnableCallback) (provider *Provider, err
133 133
 	return NewProviderWithID(name, providerIDFromName(name), callback)
134 134
 }
135 135
 
136
-// NewProviderWithID creates and registers a new ETW provider, allowing the
137
-// provider ID to be manually specified. This is most useful when there is an
138
-// existing provider ID that must be used to conform to existing diagnostic
139
-// infrastructure.
140
-func NewProviderWithID(name string, id *windows.GUID, callback EnableCallback) (provider *Provider, err error) {
141
-	providerCallbackOnce.Do(func() {
142
-		globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
143
-	})
144
-
145
-	provider = providers.newProvider()
146
-	defer func() {
147
-		if err != nil {
148
-			providers.removeProvider(provider)
149
-		}
150
-	}()
151
-	provider.ID = id
152
-	provider.callback = callback
153
-
154
-	if err := eventRegister(provider.ID, globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
155
-		return nil, err
156
-	}
157
-
158
-	metadata := &bytes.Buffer{}
159
-	binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
160
-	metadata.WriteString(name)
161
-	metadata.WriteByte(0)                                                   // Null terminator for name
162
-	binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
163
-	provider.metadata = metadata.Bytes()
164
-
165
-	if err := eventSetInformation(
166
-		provider.handle,
167
-		eventInfoClassProviderSetTraits,
168
-		uintptr(unsafe.Pointer(&provider.metadata[0])),
169
-		uint32(len(provider.metadata))); err != nil {
170
-
171
-		return nil, err
172
-	}
173
-
174
-	return provider, nil
175
-}
176
-
177 136
 // Close unregisters the provider.
178 137
 func (provider *Provider) Close() error {
138
+	if provider == nil {
139
+		return nil
140
+	}
141
+
179 142
 	providers.removeProvider(provider)
180 143
 	return eventUnregister(provider.handle)
181 144
 }
... ...
@@ -198,6 +150,10 @@ func (provider *Provider) IsEnabledForLevel(level Level) bool {
198 198
 // infrastructure, it can be useful to check if an event will actually be
199 199
 // consumed before doing expensive work to build the event data.
200 200
 func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool {
201
+	if provider == nil {
202
+		return false
203
+	}
204
+
201 205
 	if !provider.enabled {
202 206
 		return false
203 207
 	}
... ...
@@ -219,6 +175,10 @@ func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uin
219 219
 // constructed based on the EventOpt and FieldOpt values that are passed as
220 220
 // opts.
221 221
 func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
222
+	if provider == nil {
223
+		return nil
224
+	}
225
+
222 226
 	options := eventOptions{descriptor: newEventDescriptor()}
223 227
 	em := &eventMetadata{}
224 228
 	ed := &eventData{}
... ...
@@ -247,7 +207,7 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt
247 247
 		dataBlobs = [][]byte{ed.bytes()}
248 248
 	}
249 249
 
250
-	return provider.writeEventRaw(options.descriptor, nil, nil, [][]byte{em.bytes()}, dataBlobs)
250
+	return provider.writeEventRaw(options.descriptor, options.activityID, options.relatedActivityID, [][]byte{em.bytes()}, dataBlobs)
251 251
 }
252 252
 
253 253
 // writeEventRaw writes a single ETW event from the provider. This function is
... ...
@@ -259,8 +219,8 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt
259 259
 // the ETW infrastructure.
260 260
 func (provider *Provider) writeEventRaw(
261 261
 	descriptor *eventDescriptor,
262
-	activityID *windows.GUID,
263
-	relatedActivityID *windows.GUID,
262
+	activityID *guid.GUID,
263
+	relatedActivityID *guid.GUID,
264 264
 	metadataBlobs [][]byte,
265 265
 	dataBlobs [][]byte) error {
266 266
 
... ...
@@ -275,5 +235,5 @@ func (provider *Provider) writeEventRaw(
275 275
 		dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
276 276
 	}
277 277
 
278
-	return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0])
278
+	return eventWriteTransfer(provider.handle, descriptor, (*windows.GUID)(activityID), (*windows.GUID)(relatedActivityID), dataDescriptorCount, &dataDescriptors[0])
279 279
 }
280 280
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+// +build 386 arm
1
+
2
+package etw
3
+
4
+import (
5
+	"golang.org/x/sys/windows"
6
+)
7
+
8
+func low(v providerHandle) uint32 {
9
+	return uint32(v & 0xffffffff)
10
+}
11
+
12
+func high(v providerHandle) uint32 {
13
+	return low(v >> 32)
14
+}
15
+
16
+func eventUnregister(providerHandle providerHandle) (win32err error) {
17
+	return eventUnregister_32(low(providerHandle), high(providerHandle))
18
+}
19
+
20
+func eventWriteTransfer(
21
+	providerHandle providerHandle,
22
+	descriptor *eventDescriptor,
23
+	activityID *windows.GUID,
24
+	relatedActivityID *windows.GUID,
25
+	dataDescriptorCount uint32,
26
+	dataDescriptors *eventDataDescriptor) (win32err error) {
27
+
28
+	return eventWriteTransfer_32(
29
+		low(providerHandle),
30
+		high(providerHandle),
31
+		descriptor,
32
+		activityID,
33
+		relatedActivityID,
34
+		dataDescriptorCount,
35
+		dataDescriptors)
36
+}
37
+
38
+func eventSetInformation(
39
+	providerHandle providerHandle,
40
+	class eventInfoClass,
41
+	information uintptr,
42
+	length uint32) (win32err error) {
43
+
44
+	return eventSetInformation_32(
45
+		low(providerHandle),
46
+		high(providerHandle),
47
+		class,
48
+		information,
49
+		length)
50
+}
0 51
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+// +build amd64 arm64
1
+
2
+package etw
3
+
4
+import (
5
+	"golang.org/x/sys/windows"
6
+)
7
+
8
+func eventUnregister(providerHandle providerHandle) (win32err error) {
9
+	return eventUnregister_64(providerHandle)
10
+}
11
+
12
+func eventWriteTransfer(
13
+	providerHandle providerHandle,
14
+	descriptor *eventDescriptor,
15
+	activityID *windows.GUID,
16
+	relatedActivityID *windows.GUID,
17
+	dataDescriptorCount uint32,
18
+	dataDescriptors *eventDataDescriptor) (win32err error) {
19
+
20
+	return eventWriteTransfer_64(
21
+		providerHandle,
22
+		descriptor,
23
+		activityID,
24
+		relatedActivityID,
25
+		dataDescriptorCount,
26
+		dataDescriptors)
27
+}
28
+
29
+func eventSetInformation(
30
+	providerHandle providerHandle,
31
+	class eventInfoClass,
32
+	information uintptr,
33
+	length uint32) (win32err error) {
34
+
35
+	return eventSetInformation_64(
36
+		providerHandle,
37
+		class,
38
+		information,
39
+		length)
40
+}
... ...
@@ -53,7 +53,7 @@ func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext u
53 53
 	return
54 54
 }
55 55
 
56
-func eventUnregister(providerHandle providerHandle) (win32err error) {
56
+func eventUnregister_64(providerHandle providerHandle) (win32err error) {
57 57
 	r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0)
58 58
 	if r0 != 0 {
59 59
 		win32err = syscall.Errno(r0)
... ...
@@ -61,7 +61,7 @@ func eventUnregister(providerHandle providerHandle) (win32err error) {
61 61
 	return
62 62
 }
63 63
 
64
-func eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
64
+func eventWriteTransfer_64(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
65 65
 	r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
66 66
 	if r0 != 0 {
67 67
 		win32err = syscall.Errno(r0)
... ...
@@ -69,10 +69,34 @@ func eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescript
69 69
 	return
70 70
 }
71 71
 
72
-func eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
72
+func eventSetInformation_64(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
73 73
 	r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 4, uintptr(providerHandle), uintptr(class), uintptr(information), uintptr(length), 0, 0)
74 74
 	if r0 != 0 {
75 75
 		win32err = syscall.Errno(r0)
76 76
 	}
77 77
 	return
78 78
 }
79
+
80
+func eventUnregister_32(providerHandle_low uint32, providerHandle_high uint32) (win32err error) {
81
+	r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 2, uintptr(providerHandle_low), uintptr(providerHandle_high), 0)
82
+	if r0 != 0 {
83
+		win32err = syscall.Errno(r0)
84
+	}
85
+	return
86
+}
87
+
88
+func eventWriteTransfer_32(providerHandle_low uint32, providerHandle_high uint32, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
89
+	r0, _, _ := syscall.Syscall9(procEventWriteTransfer.Addr(), 7, uintptr(providerHandle_low), uintptr(providerHandle_high), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)), 0, 0)
90
+	if r0 != 0 {
91
+		win32err = syscall.Errno(r0)
92
+	}
93
+	return
94
+}
95
+
96
+func eventSetInformation_32(providerHandle_low uint32, providerHandle_high uint32, class eventInfoClass, information uintptr, length uint32) (win32err error) {
97
+	r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 5, uintptr(providerHandle_low), uintptr(providerHandle_high), uintptr(class), uintptr(information), uintptr(length), 0)
98
+	if r0 != 0 {
99
+		win32err = syscall.Errno(r0)
100
+	}
101
+	return
102
+}
... ...
@@ -1,9 +1,6 @@
1 1
 package etwlogrus
2 2
 
3 3
 import (
4
-	"fmt"
5
-	"reflect"
6
-
7 4
 	"github.com/Microsoft/go-winio/pkg/etw"
8 5
 	"github.com/sirupsen/logrus"
9 6
 )
... ...
@@ -71,7 +68,7 @@ func (h *Hook) Fire(e *logrus.Entry) error {
71 71
 	fields = append(fields, etw.StringField("Message", e.Message))
72 72
 
73 73
 	for k, v := range e.Data {
74
-		fields = append(fields, getFieldOpt(k, v))
74
+		fields = append(fields, etw.SmartField(k, v))
75 75
 	}
76 76
 
77 77
 	return h.provider.WriteEvent(
... ...
@@ -80,127 +77,6 @@ func (h *Hook) Fire(e *logrus.Entry) error {
80 80
 		fields)
81 81
 }
82 82
 
83
-// Currently, we support logging basic builtin types (int, string, etc), slices
84
-// of basic builtin types, error, types derived from the basic types (e.g. "type
85
-// foo int"), and structs (recursively logging their fields). We do not support
86
-// slices of derived types (e.g. "[]foo").
87
-//
88
-// For types that we don't support, the value is formatted via fmt.Sprint, and
89
-// we also log a message that the type is unsupported along with the formatted
90
-// type. The intent of this is to make it easier to see which types are not
91
-// supported in traces, so we can evaluate adding support for more types in the
92
-// future.
93
-func getFieldOpt(k string, v interface{}) etw.FieldOpt {
94
-	switch v := v.(type) {
95
-	case bool:
96
-		return etw.BoolField(k, v)
97
-	case []bool:
98
-		return etw.BoolArray(k, v)
99
-	case string:
100
-		return etw.StringField(k, v)
101
-	case []string:
102
-		return etw.StringArray(k, v)
103
-	case int:
104
-		return etw.IntField(k, v)
105
-	case []int:
106
-		return etw.IntArray(k, v)
107
-	case int8:
108
-		return etw.Int8Field(k, v)
109
-	case []int8:
110
-		return etw.Int8Array(k, v)
111
-	case int16:
112
-		return etw.Int16Field(k, v)
113
-	case []int16:
114
-		return etw.Int16Array(k, v)
115
-	case int32:
116
-		return etw.Int32Field(k, v)
117
-	case []int32:
118
-		return etw.Int32Array(k, v)
119
-	case int64:
120
-		return etw.Int64Field(k, v)
121
-	case []int64:
122
-		return etw.Int64Array(k, v)
123
-	case uint:
124
-		return etw.UintField(k, v)
125
-	case []uint:
126
-		return etw.UintArray(k, v)
127
-	case uint8:
128
-		return etw.Uint8Field(k, v)
129
-	case []uint8:
130
-		return etw.Uint8Array(k, v)
131
-	case uint16:
132
-		return etw.Uint16Field(k, v)
133
-	case []uint16:
134
-		return etw.Uint16Array(k, v)
135
-	case uint32:
136
-		return etw.Uint32Field(k, v)
137
-	case []uint32:
138
-		return etw.Uint32Array(k, v)
139
-	case uint64:
140
-		return etw.Uint64Field(k, v)
141
-	case []uint64:
142
-		return etw.Uint64Array(k, v)
143
-	case uintptr:
144
-		return etw.UintptrField(k, v)
145
-	case []uintptr:
146
-		return etw.UintptrArray(k, v)
147
-	case float32:
148
-		return etw.Float32Field(k, v)
149
-	case []float32:
150
-		return etw.Float32Array(k, v)
151
-	case float64:
152
-		return etw.Float64Field(k, v)
153
-	case []float64:
154
-		return etw.Float64Array(k, v)
155
-	case error:
156
-		return etw.StringField(k, v.Error())
157
-	default:
158
-		switch rv := reflect.ValueOf(v); rv.Kind() {
159
-		case reflect.Bool:
160
-			return getFieldOpt(k, rv.Bool())
161
-		case reflect.Int:
162
-			return getFieldOpt(k, int(rv.Int()))
163
-		case reflect.Int8:
164
-			return getFieldOpt(k, int8(rv.Int()))
165
-		case reflect.Int16:
166
-			return getFieldOpt(k, int16(rv.Int()))
167
-		case reflect.Int32:
168
-			return getFieldOpt(k, int32(rv.Int()))
169
-		case reflect.Int64:
170
-			return getFieldOpt(k, int64(rv.Int()))
171
-		case reflect.Uint:
172
-			return getFieldOpt(k, uint(rv.Uint()))
173
-		case reflect.Uint8:
174
-			return getFieldOpt(k, uint8(rv.Uint()))
175
-		case reflect.Uint16:
176
-			return getFieldOpt(k, uint16(rv.Uint()))
177
-		case reflect.Uint32:
178
-			return getFieldOpt(k, uint32(rv.Uint()))
179
-		case reflect.Uint64:
180
-			return getFieldOpt(k, uint64(rv.Uint()))
181
-		case reflect.Uintptr:
182
-			return getFieldOpt(k, uintptr(rv.Uint()))
183
-		case reflect.Float32:
184
-			return getFieldOpt(k, float32(rv.Float()))
185
-		case reflect.Float64:
186
-			return getFieldOpt(k, float64(rv.Float()))
187
-		case reflect.String:
188
-			return getFieldOpt(k, rv.String())
189
-		case reflect.Struct:
190
-			fields := make([]etw.FieldOpt, 0, rv.NumField())
191
-			for i := 0; i < rv.NumField(); i++ {
192
-				field := rv.Field(i)
193
-				if field.CanInterface() {
194
-					fields = append(fields, getFieldOpt(k, field.Interface()))
195
-				}
196
-			}
197
-			return etw.Struct(k, fields...)
198
-		}
199
-	}
200
-
201
-	return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v))
202
-}
203
-
204 83
 // Close cleans up the hook and closes the ETW provider. If the provder was
205 84
 // registered by etwlogrus, it will be closed as part of `Close`. If the
206 85
 // provider was passed in, it will not be closed.
207 86
new file mode 100644
... ...
@@ -0,0 +1,110 @@
0
+package guid
1
+
2
+import (
3
+	"crypto/rand"
4
+	"encoding/binary"
5
+	"encoding/json"
6
+	"fmt"
7
+	"strconv"
8
+	"strings"
9
+
10
+	"github.com/pkg/errors"
11
+	"golang.org/x/sys/windows"
12
+)
13
+
14
+var _ = (json.Marshaler)(&GUID{})
15
+var _ = (json.Unmarshaler)(&GUID{})
16
+
17
+// GUID represents a GUID/UUID. It has the same structure as
18
+// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
19
+// that type. It is defined as its own type so that stringification and
20
+// marshaling can be supported. The representation matches that used by native
21
+// Windows code.
22
+type GUID windows.GUID
23
+
24
+// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
25
+func NewV4() (*GUID, error) {
26
+	var b [16]byte
27
+	if _, err := rand.Read(b[:]); err != nil {
28
+		return nil, err
29
+	}
30
+
31
+	var g GUID
32
+	g.Data1 = binary.LittleEndian.Uint32(b[0:4])
33
+	g.Data2 = binary.LittleEndian.Uint16(b[4:6])
34
+	g.Data3 = binary.LittleEndian.Uint16(b[6:8])
35
+	copy(g.Data4[:], b[8:16])
36
+
37
+	g.Data3 = (g.Data3 & 0x0fff) | 0x4000   // Version 4 (randomly generated)
38
+	g.Data4[0] = (g.Data4[0] & 0x3f) | 0x80 // RFC4122 variant
39
+	return &g, nil
40
+}
41
+
42
+func (g *GUID) String() string {
43
+	return fmt.Sprintf(
44
+		"%08x-%04x-%04x-%04x-%012x",
45
+		g.Data1,
46
+		g.Data2,
47
+		g.Data3,
48
+		g.Data4[:2],
49
+		g.Data4[2:])
50
+}
51
+
52
+// FromString parses a string containing a GUID and returns the GUID. The only
53
+// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
54
+// format.
55
+func FromString(s string) (*GUID, error) {
56
+	if len(s) != 36 {
57
+		return nil, errors.New("invalid GUID format (length)")
58
+	}
59
+	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
60
+		return nil, errors.New("invalid GUID format (dashes)")
61
+	}
62
+
63
+	var g GUID
64
+
65
+	data1, err := strconv.ParseUint(s[0:8], 16, 32)
66
+	if err != nil {
67
+		return nil, errors.Wrap(err, "invalid GUID format (Data1)")
68
+	}
69
+	g.Data1 = uint32(data1)
70
+
71
+	data2, err := strconv.ParseUint(s[9:13], 16, 16)
72
+	if err != nil {
73
+		return nil, errors.Wrap(err, "invalid GUID format (Data2)")
74
+	}
75
+	g.Data2 = uint16(data2)
76
+
77
+	data3, err := strconv.ParseUint(s[14:18], 16, 16)
78
+	if err != nil {
79
+		return nil, errors.Wrap(err, "invalid GUID format (Data3)")
80
+	}
81
+	g.Data3 = uint16(data3)
82
+
83
+	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
84
+		v, err := strconv.ParseUint(s[x:x+2], 16, 8)
85
+		if err != nil {
86
+			return nil, errors.Wrap(err, "invalid GUID format (Data4)")
87
+		}
88
+		g.Data4[i] = uint8(v)
89
+	}
90
+
91
+	return &g, nil
92
+}
93
+
94
+// MarshalJSON marshals the GUID to JSON representation and returns it as a
95
+// slice of bytes.
96
+func (g *GUID) MarshalJSON() ([]byte, error) {
97
+	return json.Marshal(g.String())
98
+}
99
+
100
+// UnmarshalJSON unmarshals a GUID from JSON representation and sets itself to
101
+// the unmarshaled GUID.
102
+func (g *GUID) UnmarshalJSON(data []byte) error {
103
+	g2, err := FromString(strings.Trim(string(data), "\""))
104
+	if err != nil {
105
+		return err
106
+	}
107
+	*g = *g2
108
+	return nil
109
+}
... ...
@@ -1,3 +1,3 @@
1 1
 package winio
2 2
 
3
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
3
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
... ...
@@ -1,4 +1,4 @@
1
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
1
+// Code generated by 'go generate'; DO NOT EDIT.
2 2
 
3 3
 package winio
4 4
 
... ...
@@ -38,19 +38,25 @@ func errnoErr(e syscall.Errno) error {
38 38
 
39 39
 var (
40 40
 	modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
41
+	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll")
42
+	modntdll    = windows.NewLazySystemDLL("ntdll.dll")
41 43
 	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
42 44
 
43 45
 	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx")
44 46
 	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort")
45 47
 	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus")
46 48
 	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes")
49
+	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult")
47 50
 	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe")
48 51
 	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW")
49 52
 	procCreateFileW                                          = modkernel32.NewProc("CreateFileW")
50
-	procWaitNamedPipeW                                       = modkernel32.NewProc("WaitNamedPipeW")
51 53
 	procGetNamedPipeInfo                                     = modkernel32.NewProc("GetNamedPipeInfo")
52 54
 	procGetNamedPipeHandleStateW                             = modkernel32.NewProc("GetNamedPipeHandleStateW")
53 55
 	procLocalAlloc                                           = modkernel32.NewProc("LocalAlloc")
56
+	procNtCreateNamedPipeFile                                = modntdll.NewProc("NtCreateNamedPipeFile")
57
+	procRtlNtStatusToDosErrorNoTeb                           = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
58
+	procRtlDosPathNameToNtPathName_U                         = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
59
+	procRtlDefaultNpAcl                                      = modntdll.NewProc("RtlDefaultNpAcl")
54 60
 	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
55 61
 	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
56 62
 	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
... ...
@@ -69,6 +75,7 @@ var (
69 69
 	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
70 70
 	procBackupRead                                           = modkernel32.NewProc("BackupRead")
71 71
 	procBackupWrite                                          = modkernel32.NewProc("BackupWrite")
72
+	procbind                                                 = modws2_32.NewProc("bind")
72 73
 )
73 74
 
74 75
 func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
... ...
@@ -120,6 +127,24 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
120 120
 	return
121 121
 }
122 122
 
123
+func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
124
+	var _p0 uint32
125
+	if wait {
126
+		_p0 = 1
127
+	} else {
128
+		_p0 = 0
129
+	}
130
+	r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
131
+	if r1 == 0 {
132
+		if e1 != 0 {
133
+			err = errnoErr(e1)
134
+		} else {
135
+			err = syscall.EINVAL
136
+		}
137
+	}
138
+	return
139
+}
140
+
123 141
 func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
124 142
 	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
125 143
 	if r1 == 0 {
... ...
@@ -176,27 +201,6 @@ func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityA
176 176
 	return
177 177
 }
178 178
 
179
-func waitNamedPipe(name string, timeout uint32) (err error) {
180
-	var _p0 *uint16
181
-	_p0, err = syscall.UTF16PtrFromString(name)
182
-	if err != nil {
183
-		return
184
-	}
185
-	return _waitNamedPipe(_p0, timeout)
186
-}
187
-
188
-func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
189
-	r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
190
-	if r1 == 0 {
191
-		if e1 != 0 {
192
-			err = errnoErr(e1)
193
-		} else {
194
-			err = syscall.EINVAL
195
-		}
196
-	}
197
-	return
198
-}
199
-
200 179
 func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
201 180
 	r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
202 181
 	if r1 == 0 {
... ...
@@ -227,6 +231,32 @@ func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
227 227
 	return
228 228
 }
229 229
 
230
+func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
231
+	r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
232
+	status = ntstatus(r0)
233
+	return
234
+}
235
+
236
+func rtlNtStatusToDosError(status ntstatus) (winerr error) {
237
+	r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
238
+	if r0 != 0 {
239
+		winerr = syscall.Errno(r0)
240
+	}
241
+	return
242
+}
243
+
244
+func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
245
+	r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
246
+	status = ntstatus(r0)
247
+	return
248
+}
249
+
250
+func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
251
+	r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
252
+	status = ntstatus(r0)
253
+	return
254
+}
255
+
230 256
 func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
231 257
 	var _p0 *uint16
232 258
 	_p0, err = syscall.UTF16PtrFromString(accountName)
... ...
@@ -518,3 +548,15 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
518 518
 	}
519 519
 	return
520 520
 }
521
+
522
+func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
523
+	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
524
+	if r1 == socketError {
525
+		if e1 != 0 {
526
+			err = errnoErr(e1)
527
+		} else {
528
+			err = syscall.EINVAL
529
+		}
530
+	}
531
+	return
532
+}