OSDN Git Service

[cp] Build camera related goldfish HALs as brilloemulator for Brillo
[android-x86/device-generic-goldfish-opengl.git] / shared / OpenglCodecCommon / Win32PipeStream.cpp
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
34 Win32PipeStream::Win32PipeStream(size_t bufSize) :
35     SocketStream(bufSize),
36     m_pipe(INVALID_HANDLE_VALUE)
37 {
38 }
39
40 Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) :
41     SocketStream(-1, bufSize),
42     m_pipe(pipe)
43 {
44 }
45
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
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  */
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
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
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
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
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
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 }