xref: /openbmc/qemu/chardev/char-pipe.c (revision 0b8fa32f551e863bb548a11394239239270dd3dc)
1 /*
2  * QEMU System Emulator
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 #include "qapi/error.h"
27 #include "qemu/module.h"
28 #include "qemu/option.h"
29 #include "chardev/char.h"
30 
31 #ifdef _WIN32
32 #include "chardev/char-win.h"
33 #else
34 #include "chardev/char-fd.h"
35 #endif
36 
37 #ifdef _WIN32
38 #define MAXCONNECT 1
39 #define NTIMEOUT 5000
40 
41 static int win_chr_pipe_init(Chardev *chr, const char *filename,
42                              Error **errp)
43 {
44     WinChardev *s = WIN_CHARDEV(chr);
45     OVERLAPPED ov;
46     int ret;
47     DWORD size;
48     char *openname;
49 
50     s->fpipe = TRUE;
51 
52     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
53     if (!s->hsend) {
54         error_setg(errp, "Failed CreateEvent");
55         goto fail;
56     }
57     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
58     if (!s->hrecv) {
59         error_setg(errp, "Failed CreateEvent");
60         goto fail;
61     }
62 
63     openname = g_strdup_printf("\\\\.\\pipe\\%s", filename);
64     s->file = CreateNamedPipe(openname,
65                               PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
66                               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
67                               PIPE_WAIT,
68                               MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
69     g_free(openname);
70     if (s->file == INVALID_HANDLE_VALUE) {
71         error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError());
72         s->file = NULL;
73         goto fail;
74     }
75 
76     ZeroMemory(&ov, sizeof(ov));
77     ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
78     ret = ConnectNamedPipe(s->file, &ov);
79     if (ret) {
80         error_setg(errp, "Failed ConnectNamedPipe");
81         goto fail;
82     }
83 
84     ret = GetOverlappedResult(s->file, &ov, &size, TRUE);
85     if (!ret) {
86         error_setg(errp, "Failed GetOverlappedResult");
87         if (ov.hEvent) {
88             CloseHandle(ov.hEvent);
89             ov.hEvent = NULL;
90         }
91         goto fail;
92     }
93 
94     if (ov.hEvent) {
95         CloseHandle(ov.hEvent);
96         ov.hEvent = NULL;
97     }
98     qemu_add_polling_cb(win_chr_pipe_poll, chr);
99     return 0;
100 
101  fail:
102     return -1;
103 }
104 
105 static void qemu_chr_open_pipe(Chardev *chr,
106                                ChardevBackend *backend,
107                                bool *be_opened,
108                                Error **errp)
109 {
110     ChardevHostdev *opts = backend->u.pipe.data;
111     const char *filename = opts->device;
112 
113     if (win_chr_pipe_init(chr, filename, errp) < 0) {
114         return;
115     }
116 }
117 
118 #else
119 
120 static void qemu_chr_open_pipe(Chardev *chr,
121                                ChardevBackend *backend,
122                                bool *be_opened,
123                                Error **errp)
124 {
125     ChardevHostdev *opts = backend->u.pipe.data;
126     int fd_in, fd_out;
127     char *filename_in;
128     char *filename_out;
129     const char *filename = opts->device;
130 
131     filename_in = g_strdup_printf("%s.in", filename);
132     filename_out = g_strdup_printf("%s.out", filename);
133     TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
134     TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
135     g_free(filename_in);
136     g_free(filename_out);
137     if (fd_in < 0 || fd_out < 0) {
138         if (fd_in >= 0) {
139             close(fd_in);
140         }
141         if (fd_out >= 0) {
142             close(fd_out);
143         }
144         TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
145         if (fd_in < 0) {
146             error_setg_file_open(errp, errno, filename);
147             return;
148         }
149     }
150     qemu_chr_open_fd(chr, fd_in, fd_out);
151 }
152 
153 #endif /* !_WIN32 */
154 
155 static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
156                                 Error **errp)
157 {
158     const char *device = qemu_opt_get(opts, "path");
159     ChardevHostdev *dev;
160 
161     if (device == NULL) {
162         error_setg(errp, "chardev: pipe: no device path given");
163         return;
164     }
165     backend->type = CHARDEV_BACKEND_KIND_PIPE;
166     dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1);
167     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
168     dev->device = g_strdup(device);
169 }
170 
171 static void char_pipe_class_init(ObjectClass *oc, void *data)
172 {
173     ChardevClass *cc = CHARDEV_CLASS(oc);
174 
175     cc->parse = qemu_chr_parse_pipe;
176     cc->open = qemu_chr_open_pipe;
177 }
178 
179 static const TypeInfo char_pipe_type_info = {
180     .name = TYPE_CHARDEV_PIPE,
181 #ifdef _WIN32
182     .parent = TYPE_CHARDEV_WIN,
183 #else
184     .parent = TYPE_CHARDEV_FD,
185 #endif
186     .class_init = char_pipe_class_init,
187 };
188 
189 static void register_types(void)
190 {
191     type_register_static(&char_pipe_type_info);
192 }
193 
194 type_init(register_types);
195