]> git.proxmox.com Git - mirror_ovs.git/blob - lib/stream-windows.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / stream-windows.c
1 /*
2 * Copyright (c) 2016, 2017 Cloudbase Solutions Srl
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #include <errno.h>
19 #include <sys/types.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include "openvswitch/poll-loop.h"
24 #include "dirs.h"
25 #include "fatal-signal.h"
26 #include "util.h"
27 #include "stream-provider.h"
28 #include "openvswitch/vlog.h"
29
30 VLOG_DEFINE_THIS_MODULE(stream_windows);
31
32 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 25);
33
34 static void maybe_unlink_and_free(char *path);
35
36 /* Suggested buffer size at the creation of the named pipe for reading and
37 * and writing operations. */
38 #define BUFSIZE 65000
39
40 /* Default prefix of a local named pipe. */
41 #define LOCAL_PREFIX "\\\\.\\pipe\\"
42
43 /* Size of the allowed PSIDs for securing Named Pipe. */
44 #define ALLOWED_PSIDS_SIZE 3
45
46 /* This function has the purpose to remove all the slashes received in s. */
47 static char *
48 remove_slashes(char *s)
49 {
50 char *p1, *p2;
51 p1 = p2 = s;
52
53 while (*p1) {
54 if ((*p1) == '\\' || (*p1) == '/') {
55 p1++;
56 } else {
57 *p2 = *p1;
58 p2++;
59 p1++;
60 }
61 }
62 *p2 = '\0';
63 return s;
64 }
65
66 /* Active named pipe. */
67 struct windows_stream
68 {
69 struct stream stream;
70 HANDLE fd;
71 /* Overlapped operations used for reading/writing. */
72 OVERLAPPED read;
73 OVERLAPPED write;
74 /* Flag to check if a reading/writing operation is pending. */
75 bool read_pending;
76 bool write_pending;
77 /* Flag to check if fd is a server HANDLE. In the case of a server handle
78 * we have to issue a disconnect before closing the actual handle. */
79 bool server;
80 bool retry_connect;
81 char *pipe_path;
82 };
83
84 static struct windows_stream *
85 stream_windows_cast(struct stream *stream)
86 {
87 stream_assert_class(stream, &windows_stream_class);
88 return CONTAINER_OF(stream, struct windows_stream, stream);
89 }
90
91 static HANDLE
92 create_snpipe(char *path)
93 {
94 return CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
95 OPEN_EXISTING,
96 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |
97 FILE_FLAG_NO_BUFFERING,
98 NULL);
99 }
100
101 /* Active named pipe open. */
102 static int
103 windows_open(const char *name, char *suffix, struct stream **streamp,
104 uint8_t dscp OVS_UNUSED)
105 {
106 char *connect_path;
107 HANDLE npipe;
108 DWORD mode = PIPE_READMODE_BYTE;
109 char *path;
110 FILE *file;
111 bool retry = false;
112 /* If the path does not contain a ':', assume it is relative to
113 * OVS_RUNDIR. */
114 if (!strchr(suffix, ':')) {
115 path = xasprintf("%s/%s", ovs_rundir(), suffix);
116 } else {
117 path = xstrdup(suffix);
118 }
119
120 /* In case of "unix:" argument, the assumption is that there is a file
121 * created in the path (name). */
122 file = fopen(path, "r");
123 if (!file) {
124 free(path);
125 VLOG_DBG_RL(&rl, "%s: could not open %s (%s)", name, suffix,
126 ovs_strerror(errno));
127 return ENOENT;
128 } else {
129 fclose(file);
130 }
131
132 /* Valid pipe names do not have slashes. The assumption is that the named
133 * pipe was created with the name "path", with slashes removed and the
134 * default prefix \\.\pipe\ appended.
135 * Strip the slashes from the parameter name and append the default prefix.
136 */
137 connect_path = xasprintf("%s%s", LOCAL_PREFIX, remove_slashes(path));
138 free(path);
139
140 /* Try to connect to the named pipe. In case all pipe instances are
141 * busy we set the retry flag to true and retry again during the
142 * connect function. Use overlapped flag and file no buffering to ensure
143 * asynchronous operations. */
144 npipe = create_snpipe(connect_path);
145
146 if (npipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) {
147 retry = true;
148 }
149
150 if (!retry && npipe == INVALID_HANDLE_VALUE) {
151 VLOG_ERR_RL(&rl, "Could not connect to named pipe: %s",
152 ovs_lasterror_to_string());
153 free(connect_path);
154 return ENOENT;
155 }
156 if (!retry && !SetNamedPipeHandleState(npipe, &mode, NULL, NULL)) {
157 VLOG_ERR_RL(&rl, "Could not set named pipe options: %s",
158 ovs_lasterror_to_string());
159 free(connect_path);
160 CloseHandle(npipe);
161 return ENOENT;
162 }
163 struct windows_stream *s = xmalloc(sizeof *s);
164 stream_init(&s->stream, &windows_stream_class, 0, xstrdup(name));
165 s->pipe_path = connect_path;
166 s->fd = npipe;
167 /* This is an active stream. */
168 s->server = false;
169 /* Create events for reading and writing to be signaled later. */
170 memset(&s->read, 0, sizeof(s->read));
171 memset(&s->write, 0, sizeof(s->write));
172 s->read.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
173 s->write.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
174 /* Initial read and write operations are not pending. */
175 s->read_pending = false;
176 s->write_pending = false;
177 s->retry_connect = retry;
178 *streamp = &s->stream;
179 return 0;
180 }
181
182 /* Active named pipe close. */
183 static void
184 windows_close(struct stream *stream)
185 {
186 struct windows_stream *s = stream_windows_cast(stream);
187 /* Disconnect the named pipe in case it was created from a passive stream.
188 */
189 if (s->server) {
190 /* Flush the pipe to allow the client to read the pipe's contents
191 * before disconnecting. */
192 FlushFileBuffers(s->fd);
193 DisconnectNamedPipe(s->fd);
194 }
195 CloseHandle(s->fd);
196 CloseHandle(s->read.hEvent);
197 CloseHandle(s->write.hEvent);
198 if (s->pipe_path) {
199 free(s->pipe_path);
200 }
201 free(s);
202 }
203
204 /* Active named pipe connect. */
205 static int
206 windows_connect(struct stream *stream)
207 {
208 struct windows_stream *s = stream_windows_cast(stream);
209
210 if (!s->retry_connect) {
211 return 0;
212 } else {
213 HANDLE npipe;
214 npipe = create_snpipe(s->pipe_path);
215 if (npipe == INVALID_HANDLE_VALUE) {
216 if (GetLastError() == ERROR_PIPE_BUSY) {
217 return EAGAIN;
218 } else {
219 s->retry_connect = false;
220 return ENOENT;
221 }
222 }
223 s->retry_connect = false;
224 s->fd = npipe;
225 return 0;
226 }
227 }
228
229 /* Active named pipe receive. */
230 static ssize_t
231 windows_recv(struct stream *stream, void *buffer, size_t n)
232 {
233 struct windows_stream *s = stream_windows_cast(stream);
234 ssize_t retval = 0;
235 boolean result = false;
236 DWORD last_error = 0;
237 LPOVERLAPPED ov = NULL;
238 ov = &s->read;
239
240 /* If the read operation was pending, we verify its result. */
241 if (s->read_pending) {
242 if (!GetOverlappedResult(s->fd, ov, &(DWORD)retval, FALSE)) {
243 last_error = GetLastError();
244 if (last_error == ERROR_IO_INCOMPLETE) {
245 /* If the operation is still pending, retry again. */
246 s->read_pending = true;
247 return -EAGAIN;
248 } else if (last_error == ERROR_PIPE_NOT_CONNECTED
249 || last_error == ERROR_BAD_PIPE
250 || last_error == ERROR_NO_DATA
251 || last_error == ERROR_BROKEN_PIPE) {
252 /* If the pipe was disconnected, return 0. */
253 return 0;
254 } else {
255 VLOG_ERR_RL(&rl, "Could not receive data on named pipe. Last "
256 "error: %s", ovs_lasterror_to_string());
257 return -EINVAL;
258 }
259 }
260 s->read_pending = false;
261 return retval;
262 }
263
264 result = ReadFile(s->fd, buffer, n, &(DWORD)retval, ov);
265
266 if (!result && GetLastError() == ERROR_IO_PENDING) {
267 /* Mark the read operation as pending. */
268 s->read_pending = true;
269 return -EAGAIN;
270 } else if (!result) {
271 last_error = GetLastError();
272 if (last_error == ERROR_PIPE_NOT_CONNECTED
273 || last_error == ERROR_BAD_PIPE
274 || last_error == ERROR_NO_DATA
275 || last_error == ERROR_BROKEN_PIPE) {
276 /* If the pipe was disconnected, return 0. */
277 return 0;
278 }
279 VLOG_ERR_RL(&rl, "Could not receive data synchronous on named pipe."
280 "Last error: %s", ovs_lasterror_to_string());
281 return -EINVAL;
282 }
283
284 return retval;
285 }
286
287 /* Active named pipe send. */
288 static ssize_t
289 windows_send(struct stream *stream, const void *buffer, size_t n)
290 {
291 struct windows_stream *s = stream_windows_cast(stream);
292 ssize_t retval = 0;
293 boolean result = false;
294 DWORD last_error = 0;
295 LPOVERLAPPED ov = NULL;
296 ov = &s->write;
297
298 /* If the send operation was pending, we verify the result. */
299 if (s->write_pending) {
300 if (!GetOverlappedResult(s->fd, ov, &(DWORD)retval, FALSE)) {
301 last_error = GetLastError();
302 if (last_error == ERROR_IO_INCOMPLETE) {
303 /* If the operation is still pending, retry again. */
304 s->write_pending = true;
305 return -EAGAIN;
306 } else if (last_error == ERROR_PIPE_NOT_CONNECTED
307 || last_error == ERROR_BAD_PIPE
308 || last_error == ERROR_NO_DATA
309 || last_error == ERROR_BROKEN_PIPE) {
310 /* If the pipe was disconnected, return connection reset. */
311 return -EPIPE;
312 } else {
313 VLOG_ERR_RL(&rl, "Could not send data on named pipe. Last "
314 "error: %s", ovs_lasterror_to_string());
315 return -EINVAL;
316 }
317 }
318 s->write_pending = false;
319 return retval;
320 }
321
322 result = WriteFile(s->fd, buffer, n, &(DWORD)retval, ov);
323 last_error = GetLastError();
324 if (!result && last_error == ERROR_IO_PENDING) {
325 /* Mark the send operation as pending. */
326 s->write_pending = true;
327 return -EAGAIN;
328 } else if (!result && (last_error == ERROR_PIPE_NOT_CONNECTED
329 || last_error == ERROR_BAD_PIPE
330 || last_error == ERROR_NO_DATA
331 || last_error == ERROR_BROKEN_PIPE)) {
332 /* If the pipe was disconnected, return connection reset. */
333 return -EPIPE;
334 } else if (!result) {
335 VLOG_ERR_RL(&rl, "Could not send data on synchronous named pipe. Last "
336 "error: %s", ovs_lasterror_to_string());
337 return -EINVAL;
338 }
339 return (retval > 0 ? retval : -EAGAIN);
340 }
341
342 /* Active named pipe wait. */
343 static void
344 windows_wait(struct stream *stream, enum stream_wait_type wait)
345 {
346 struct windows_stream *s = stream_windows_cast(stream);
347 switch (wait) {
348 case STREAM_SEND:
349 poll_wevent_wait(s->write.hEvent);
350 break;
351
352 case STREAM_CONNECT:
353 poll_immediate_wake();
354 break;
355
356 case STREAM_RECV:
357 poll_wevent_wait(s->read.hEvent);
358 break;
359
360 default:
361 OVS_NOT_REACHED();
362 }
363 }
364
365 /* Passive named pipe. */
366 const struct stream_class windows_stream_class = {
367 "unix", /* name */
368 false, /* needs_probes */
369 windows_open, /* open */
370 windows_close, /* close */
371 windows_connect, /* connect */
372 windows_recv, /* recv */
373 windows_send, /* send */
374 NULL, /* run */
375 NULL, /* run_wait */
376 windows_wait, /* wait */
377 };
378
379 struct pwindows_pstream
380 {
381 struct pstream pstream;
382 HANDLE fd;
383 /* Unlink path to be deleted during close. */
384 char *unlink_path;
385 /* Overlapped operation used for connect. */
386 OVERLAPPED connect;
387 /* Flag to check if an operation is pending. */
388 bool pending;
389 /* String used to create the named pipe. */
390 char *pipe_path;
391 };
392
393 const struct pstream_class pwindows_pstream_class;
394
395 static struct pwindows_pstream *
396 pwindows_pstream_cast(struct pstream *pstream)
397 {
398 pstream_assert_class(pstream, &pwindows_pstream_class);
399 return CONTAINER_OF(pstream, struct pwindows_pstream, pstream);
400 }
401
402 /* Create a named pipe with read/write access, overlapped, message mode for
403 * writing, byte mode for reading and with a maximum of 64 active instances. */
404 static HANDLE
405 create_pnpipe(char *name)
406 {
407 SECURITY_ATTRIBUTES sa;
408 SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
409 DWORD aclSize;
410 PSID allowedPsid[ALLOWED_PSIDS_SIZE];
411 PSID remoteAccessSid;
412 PACL acl = NULL;
413 PSECURITY_DESCRIPTOR psd = NULL;
414 HANDLE npipe;
415 HANDLE hToken = NULL;
416 DWORD dwBufSize = 0;
417 PTOKEN_USER pTokenUsr = NULL;
418
419 /* Disable access over network. */
420 if (!AllocateAndInitializeSid(&sia, 1, SECURITY_NETWORK_RID,
421 0, 0, 0, 0, 0, 0, 0, &remoteAccessSid)) {
422 VLOG_ERR_RL(&rl, "Error creating Remote Access SID.");
423 goto handle_error;
424 }
425
426 aclSize = sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) +
427 GetLengthSid(remoteAccessSid) - sizeof(DWORD);
428
429 /* Allow Windows Services to access the Named Pipe. */
430 if (!AllocateAndInitializeSid(&sia, 1, SECURITY_LOCAL_SYSTEM_RID,
431 0, 0, 0, 0, 0, 0, 0, &allowedPsid[0])) {
432 VLOG_ERR_RL(&rl, "Error creating Services SID.");
433 goto handle_error;
434 }
435
436 /* Allow Administrators to access the Named Pipe. */
437 if (!AllocateAndInitializeSid(&sia, 2, SECURITY_BUILTIN_DOMAIN_RID,
438 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
439 &allowedPsid[1])) {
440 VLOG_ERR_RL(&rl, "Error creating Administrator SID.");
441 goto handle_error;
442 }
443
444 /* Open the access token of calling process */
445 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
446 VLOG_ERR_RL(&rl, "Error opening access token of calling process.");
447 goto handle_error;
448 }
449
450 /* get the buffer size buffer needed for SID */
451 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufSize);
452
453 pTokenUsr = xmalloc(dwBufSize);
454 memset(pTokenUsr, 0, dwBufSize);
455
456 /* Retrieve the token information in a TOKEN_USER structure. */
457 if (!GetTokenInformation(hToken, TokenUser, pTokenUsr, dwBufSize,
458 &dwBufSize)) {
459 VLOG_ERR_RL(&rl, "Error retrieving token information.");
460 goto handle_error;
461 }
462 CloseHandle(hToken);
463
464 if (!IsValidSid(pTokenUsr->User.Sid)) {
465 VLOG_ERR_RL(&rl, "Invalid SID.");
466 goto handle_error;
467 }
468 allowedPsid[2] = pTokenUsr->User.Sid;
469
470 for (int i = 0; i < ALLOWED_PSIDS_SIZE; i++) {
471 aclSize += sizeof(ACCESS_ALLOWED_ACE) +
472 GetLengthSid(allowedPsid[i]) -
473 sizeof(DWORD);
474 }
475
476 acl = xmalloc(aclSize);
477 if (!InitializeAcl(acl, aclSize, ACL_REVISION)) {
478 VLOG_ERR_RL(&rl, "Error initializing ACL.");
479 goto handle_error;
480 }
481
482 /* Add denied ACL. */
483 if (!AddAccessDeniedAce(acl, ACL_REVISION,
484 GENERIC_ALL, remoteAccessSid)) {
485 VLOG_ERR_RL(&rl, "Error adding remote access ACE.");
486 goto handle_error;
487 }
488
489 /* Add allowed ACLs. */
490 for (int i = 0; i < ALLOWED_PSIDS_SIZE; i++) {
491 if (!AddAccessAllowedAce(acl, ACL_REVISION,
492 GENERIC_ALL, allowedPsid[i])) {
493 VLOG_ERR_RL(&rl, "Error adding ACE.");
494 goto handle_error;
495 }
496 }
497
498 psd = xmalloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
499 if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) {
500 VLOG_ERR_RL(&rl, "Error initializing Security Descriptor.");
501 goto handle_error;
502 }
503
504 /* Set DACL. */
505 if (!SetSecurityDescriptorDacl(psd, TRUE, acl, FALSE)) {
506 VLOG_ERR_RL(&rl, "Error while setting DACL.");
507 goto handle_error;
508 }
509
510 sa.nLength = sizeof sa;
511 sa.bInheritHandle = TRUE;
512 sa.lpSecurityDescriptor = psd;
513
514 if (strlen(name) > 256) {
515 VLOG_ERR_RL(&rl, "Named pipe name too long.");
516 goto handle_error;
517 }
518
519 npipe = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
520 PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE | PIPE_WAIT,
521 64, BUFSIZE, BUFSIZE, 0, &sa);
522 free(pTokenUsr);
523 free(acl);
524 free(psd);
525 return npipe;
526
527 handle_error:
528 free(pTokenUsr);
529 free(acl);
530 free(psd);
531 return INVALID_HANDLE_VALUE;
532 }
533
534 /* Passive named pipe connect. This function creates a new named pipe and
535 * passes the old handle to the active stream. */
536 static int
537 pwindows_accept(struct pstream *pstream, struct stream **new_streamp)
538 {
539 struct pwindows_pstream *p = pwindows_pstream_cast(pstream);
540 DWORD last_error = 0;
541 DWORD cbRet;
542 HANDLE npipe;
543
544 /* If the connect operation was pending, verify the result. */
545 if (p->pending) {
546 if (!GetOverlappedResult(p->fd, &p->connect, &cbRet, FALSE)) {
547 last_error = GetLastError();
548 if (last_error == ERROR_IO_INCOMPLETE) {
549 /* If the operation is still pending, retry again. */
550 p->pending = true;
551 return EAGAIN;
552 } else {
553 VLOG_ERR_RL(&rl, "Could not connect named pipe. Last "
554 "error: %s", ovs_lasterror_to_string());
555 DisconnectNamedPipe(p->fd);
556 return EINVAL;
557 }
558 }
559 p->pending = false;
560 }
561
562 if (!p->pending && !ConnectNamedPipe(p->fd, &p->connect)) {
563 last_error = GetLastError();
564 if (last_error == ERROR_IO_PENDING) {
565 /* Mark the accept operation as pending. */
566 p->pending = true;
567 return EAGAIN;
568 } else if (last_error != ERROR_PIPE_CONNECTED) {
569 VLOG_ERR_RL(&rl, "Could not connect synchronous named pipe. Last "
570 "error: %s", ovs_lasterror_to_string());
571 DisconnectNamedPipe(p->fd);
572 return EINVAL;
573 } else {
574 /* If the pipe is connected, signal an event. */
575 SetEvent(&p->connect.hEvent);
576 }
577 }
578
579 npipe = create_pnpipe(p->pipe_path);
580 if (npipe == INVALID_HANDLE_VALUE) {
581 VLOG_ERR_RL(&rl, "Could not create a new named pipe after connect. ",
582 ovs_lasterror_to_string());
583 return ENOENT;
584 }
585
586 /* Give the handle p->fd to the new created active stream and specify it
587 * was created by an active stream. */
588 struct windows_stream *p_temp = xmalloc(sizeof *p_temp);
589 stream_init(&p_temp->stream, &windows_stream_class, 0, xstrdup("unix"));
590 p_temp->fd = p->fd;
591 /* Specify it was created by a passive stream. */
592 p_temp->server = true;
593 /* Create events for read/write operations. */
594 memset(&p_temp->read, 0, sizeof(p_temp->read));
595 memset(&p_temp->write, 0, sizeof(p_temp->write));
596 p_temp->read.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
597 p_temp->write.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
598 p_temp->read_pending = false;
599 p_temp->write_pending = false;
600 p_temp->retry_connect = false;
601 p_temp->pipe_path = NULL;
602 *new_streamp = &p_temp->stream;
603
604 /* The passive handle p->fd will be the new created handle. */
605 p->fd = npipe;
606 memset(&p->connect, 0, sizeof(p->connect));
607 p->connect.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
608 p->pending = false;
609 return 0;
610 }
611
612 /* Passive named pipe close. */
613 static void
614 pwindows_close(struct pstream *pstream)
615 {
616 struct pwindows_pstream *p = pwindows_pstream_cast(pstream);
617 DisconnectNamedPipe(p->fd);
618 CloseHandle(p->fd);
619 CloseHandle(p->connect.hEvent);
620 maybe_unlink_and_free(p->unlink_path);
621 free(p->pipe_path);
622 free(p);
623 }
624
625 /* Passive named pipe wait. */
626 static void
627 pwindows_wait(struct pstream *pstream)
628 {
629 struct pwindows_pstream *p = pwindows_pstream_cast(pstream);
630 poll_wevent_wait(p->connect.hEvent);
631 }
632
633 /* Passive named pipe. */
634 static int
635 pwindows_open(const char *name OVS_UNUSED, char *suffix,
636 struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
637 {
638 char *bind_path;
639 int error;
640 HANDLE npipe;
641 char *orig_path;
642
643 char *path;
644 if (!strchr(suffix, ':')) {
645 path = xasprintf("%s/%s", ovs_rundir(), suffix);
646 } else {
647 path = xstrdup(suffix);
648 }
649
650 /* Try to create a file under the path location. */
651 FILE *file = fopen(path, "w");
652 if (!file) {
653 free(path);
654 error = errno;
655 VLOG_DBG_RL(&rl, "could not open %s (%s)", path, ovs_strerror(error));
656 return error;
657 } else {
658 fclose(file);
659 }
660
661 orig_path = xstrdup(path);
662 /* Strip slashes from path and create a named pipe using that newly created
663 * string. */
664 bind_path = xasprintf("%s%s", LOCAL_PREFIX, remove_slashes(path));
665 free(path);
666
667 npipe = create_pnpipe(bind_path);
668
669 if (npipe == INVALID_HANDLE_VALUE) {
670 VLOG_ERR_RL(&rl, "Could not create named pipe. Last error: %s",
671 ovs_lasterror_to_string());
672 return ENOENT;
673 }
674
675 struct pwindows_pstream *p = xmalloc(sizeof *p);
676 pstream_init(&p->pstream, &pwindows_pstream_class, xstrdup(name));
677 p->fd = npipe;
678 p->unlink_path = orig_path;
679 memset(&p->connect, 0, sizeof(p->connect));
680 p->connect.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
681 p->pending = false;
682 p->pipe_path = bind_path;
683 *pstreamp = &p->pstream;
684 return 0;
685 }
686
687 const struct pstream_class pwindows_pstream_class = {
688 "punix",
689 false, /* probes */
690 pwindows_open, /* open */
691 pwindows_close, /* close */
692 pwindows_accept, /* accept */
693 pwindows_wait, /* wait */
694 };
695
696 /* Helper functions. */
697 static void
698 maybe_unlink_and_free(char *path)
699 {
700 if (path) {
701 fatal_signal_unlink_file_now(path);
702 free(path);
703 }
704 }