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
34Win32PipeStream::Win32PipeStream(size_t bufSize) :
35    SocketStream(bufSize),
36    m_pipe(INVALID_HANDLE_VALUE)
37{
38}
39
40Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) :
41    SocketStream(-1, bufSize),
42    m_pipe(pipe)
43{
44}
45
46Win32PipeStream::~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 */
56static void
57make_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 */
76int Win32PipeStream::listen(unsigned short port)
77{
78    // just save the port number for accept()
79    m_port = port;
80    return 0;
81}
82
83SocketStream * 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
123int 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
177int 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
197const 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
220const 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