1 /*
2 * Copyright (C) 2011 The Android Open Source Project
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 #include "Win32PipeStream.h"
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <windows.h>
24
25 #ifndef _WIN32
26 #error ONLY BUILD THIS SOURCE FILE FOR WINDOWS!
27 #endif
28
29 /* The official documentation states that the name of a given named
30 * pipe cannot be more than 256 characters long.
31 */
32 #define NAMED_PIPE_MAX 256
33
Win32PipeStream(size_t bufSize)34 Win32PipeStream::Win32PipeStream(size_t bufSize) :
35 SocketStream(bufSize),
36 m_pipe(INVALID_HANDLE_VALUE)
37 {
38 }
39
Win32PipeStream(HANDLE pipe,size_t bufSize)40 Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) :
41 SocketStream(-1, bufSize),
42 m_pipe(pipe)
43 {
44 }
45
~Win32PipeStream()46 Win32PipeStream::~Win32PipeStream()
47 {
48 if (m_pipe != INVALID_HANDLE_VALUE) {
49 CloseHandle(m_pipe);
50 m_pipe = INVALID_HANDLE_VALUE;
51 }
52 }
53
54 /* Initialize the pipe name corresponding to a given port
55 */
56 static void
make_pipe_name(char * path,size_t pathlen,int port_number)57 make_pipe_name(char *path, size_t pathlen, int port_number)
58 {
59 snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number);
60 }
61
62
63 /* Technical note: Named pipes work differently from BSD Sockets.
64 * One does not create/bind a pipe, and collect a new handle each
65 * time a client connects with accept().
66 *
67 * Instead, the server creates a new pipe instance each time it wants
68 * to get a new client connection, then calls ConnectNamedPipe() to
69 * wait for a connection.
70 *
71 * So listen() is a no-op, and accept() really creates the pipe handle.
72 *
73 * Also, connect() must create a pipe handle with CreateFile() and
74 * wait for a server instance with WaitNamedPipe()
75 */
listen(unsigned short port)76 int Win32PipeStream::listen(unsigned short port)
77 {
78 // just save the port number for accept()
79 m_port = port;
80 return 0;
81 }
82
accept()83 SocketStream * Win32PipeStream::accept()
84 {
85 char path[NAMED_PIPE_MAX+1];
86 SocketStream* clientStream;
87 HANDLE pipe;
88
89 make_pipe_name(path, sizeof(path), m_port);
90
91 pipe = ::CreateNamedPipe(
92 path, // pipe name
93 PIPE_ACCESS_DUPLEX, // read-write access
94 PIPE_TYPE_BYTE | // byte-oriented writes
95 PIPE_READMODE_BYTE | // byte-oriented reads
96 PIPE_WAIT, // blocking operations
97 PIPE_UNLIMITED_INSTANCES, // no limit on clients
98 4096, // input buffer size
99 4096, // output buffer size
100 0, // client time-out
101 NULL); // default security attributes
102
103 if (pipe == INVALID_HANDLE_VALUE) {
104 ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError());
105 return NULL;
106 }
107
108 // Stupid Win32 API design: If a client is already connected, then
109 // ConnectNamedPipe will return 0, and GetLastError() will return
110 // ERROR_PIPE_CONNECTED. This is not an error! It just means that the
111 // function didn't have to wait.
112 //
113 if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) {
114 ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
115 CloseHandle(pipe);
116 return NULL;
117 }
118
119 clientStream = new Win32PipeStream(pipe, m_bufsize);
120 return clientStream;
121 }
122
connect(unsigned short port)123 int Win32PipeStream::connect(unsigned short port)
124 {
125 char path[NAMED_PIPE_MAX+1];
126 HANDLE pipe;
127 int tries = 10;
128
129 make_pipe_name(path, sizeof(path), port);
130
131 /* We're going to loop in order to wait for the pipe server to
132 * be setup properly.
133 */
134 for (; tries > 0; tries--) {
135 pipe = ::CreateFile(
136 path, // pipe name
137 GENERIC_READ | GENERIC_WRITE, // read & write
138 0, // no sharing
139 NULL, // default security attrs
140 OPEN_EXISTING, // open existing pipe
141 0, // default attributes
142 NULL); // no template file
143
144 /* If we have a valid pipe handle, break from the loop */
145 if (pipe != INVALID_HANDLE_VALUE) {
146 break;
147 }
148
149 /* We can get here if the pipe is busy, i.e. if the server hasn't
150 * create a new pipe instance to service our request. In which case
151 * GetLastError() will return ERROR_PIPE_BUSY.
152 *
153 * If so, then use WaitNamedPipe() to wait for a decent time
154 * to try again.
155 */
156 if (GetLastError() != ERROR_PIPE_BUSY) {
157 /* Not ERROR_PIPE_BUSY */
158 ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError());
159 errno = EINVAL;
160 return -1;
161 }
162
163 /* Wait for 5 seconds */
164 if ( !WaitNamedPipe(path, 5000) ) {
165 ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
166 errno = EINVAL;
167 return -1;
168 }
169 }
170
171 m_pipe = pipe;
172 return 0;
173 }
174
175 /* Special buffer methods, since we can't use socket functions here */
176
commitBuffer(size_t size)177 int Win32PipeStream::commitBuffer(size_t size)
178 {
179 if (m_pipe == INVALID_HANDLE_VALUE)
180 return -1;
181
182 size_t res = size;
183 int retval = 0;
184
185 while (res > 0) {
186 DWORD written;
187 if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) {
188 retval = -1;
189 ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError());
190 break;
191 }
192 res -= written;
193 }
194 return retval;
195 }
196
readFully(void * buf,size_t len)197 const unsigned char *Win32PipeStream::readFully(void *buf, size_t len)
198 {
199 const unsigned char* ret = NULL;
200
201 if (m_pipe == INVALID_HANDLE_VALUE)
202 return NULL;
203
204 if (!buf) {
205 return NULL; // do not allow NULL buf in that implementation
206 }
207
208 size_t res = len;
209 while (res > 0) {
210 DWORD readcount = 0;
211 if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) {
212 errno = (int)GetLastError();
213 return NULL;
214 }
215 res -= readcount;
216 }
217 return (const unsigned char *)buf;
218 }
219
read(void * buf,size_t * inout_len)220 const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len)
221 {
222 size_t len = *inout_len;
223 DWORD readcount;
224
225 if (m_pipe == INVALID_HANDLE_VALUE)
226 return NULL;
227
228 if (!buf) {
229 return NULL; // do not allow NULL buf in that implementation
230 }
231
232 if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) {
233 errno = (int)GetLastError();
234 return NULL;
235 }
236
237 *inout_len = (size_t)readcount;
238 return (const unsigned char *)buf;
239 }
240