diff options
Diffstat (limited to 'opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp')
-rw-r--r-- | opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp b/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp new file mode 100644 index 0000000..e1a0b9b --- /dev/null +++ b/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp @@ -0,0 +1,239 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "Win32PipeStream.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <windows.h> + +#ifndef _WIN32 +#error ONLY BUILD THIS SOURCE FILE FOR WINDOWS! +#endif + +/* The official documentation states that the name of a given named + * pipe cannot be more than 256 characters long. + */ +#define NAMED_PIPE_MAX 256 + +Win32PipeStream::Win32PipeStream(size_t bufSize) : + SocketStream(bufSize), + m_pipe(INVALID_HANDLE_VALUE) +{ +} + +Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) : + SocketStream(-1, bufSize), + m_pipe(pipe) +{ +} + +Win32PipeStream::~Win32PipeStream() +{ + if (m_pipe != INVALID_HANDLE_VALUE) { + CloseHandle(m_pipe); + m_pipe = INVALID_HANDLE_VALUE; + } +} + +/* Initialize the pipe name corresponding to a given port + */ +static void +make_pipe_name(char *path, size_t pathlen, int port_number) +{ + snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number); +} + + +/* Technical note: Named pipes work differently from BSD Sockets. + * One does not create/bind a pipe, and collect a new handle each + * time a client connects with accept(). + * + * Instead, the server creates a new pipe instance each time it wants + * to get a new client connection, then calls ConnectNamedPipe() to + * wait for a connection. + * + * So listen() is a no-op, and accept() really creates the pipe handle. + * + * Also, connect() must create a pipe handle with CreateFile() and + * wait for a server instance with WaitNamedPipe() + */ +int Win32PipeStream::listen(unsigned short port) +{ + // just save the port number for accept() + m_port = port; + return 0; +} + +SocketStream * Win32PipeStream::accept() +{ + char path[NAMED_PIPE_MAX+1]; + SocketStream* clientStream; + HANDLE pipe; + + make_pipe_name(path, sizeof(path), m_port); + + pipe = ::CreateNamedPipe( + path, // pipe name + PIPE_ACCESS_DUPLEX, // read-write access + PIPE_TYPE_BYTE | // byte-oriented writes + PIPE_READMODE_BYTE | // byte-oriented reads + PIPE_WAIT, // blocking operations + PIPE_UNLIMITED_INSTANCES, // no limit on clients + 4096, // input buffer size + 4096, // output buffer size + 0, // client time-out + NULL); // default security attributes + + if (pipe == INVALID_HANDLE_VALUE) { + ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError()); + return NULL; + } + + // Stupid Win32 API design: If a client is already connected, then + // ConnectNamedPipe will return 0, and GetLastError() will return + // ERROR_PIPE_CONNECTED. This is not an error! It just means that the + // function didn't have to wait. + // + if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) { + ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); + CloseHandle(pipe); + return NULL; + } + + clientStream = new Win32PipeStream(pipe, m_bufsize); + return clientStream; +} + +int Win32PipeStream::connect(unsigned short port) +{ + char path[NAMED_PIPE_MAX+1]; + HANDLE pipe; + int tries = 10; + + make_pipe_name(path, sizeof(path), port); + + /* We're going to loop in order to wait for the pipe server to + * be setup properly. + */ + for (; tries > 0; tries--) { + pipe = ::CreateFile( + path, // pipe name + GENERIC_READ | GENERIC_WRITE, // read & write + 0, // no sharing + NULL, // default security attrs + OPEN_EXISTING, // open existing pipe + 0, // default attributes + NULL); // no template file + + /* If we have a valid pipe handle, break from the loop */ + if (pipe != INVALID_HANDLE_VALUE) { + break; + } + + /* We can get here if the pipe is busy, i.e. if the server hasn't + * create a new pipe instance to service our request. In which case + * GetLastError() will return ERROR_PIPE_BUSY. + * + * If so, then use WaitNamedPipe() to wait for a decent time + * to try again. + */ + if (GetLastError() != ERROR_PIPE_BUSY) { + /* Not ERROR_PIPE_BUSY */ + ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError()); + errno = EINVAL; + return -1; + } + + /* Wait for 5 seconds */ + if ( !WaitNamedPipe(path, 5000) ) { + ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); + errno = EINVAL; + return -1; + } + } + + m_pipe = pipe; + return 0; +} + +/* Special buffer methods, since we can't use socket functions here */ + +int Win32PipeStream::commitBuffer(size_t size) +{ + if (m_pipe == INVALID_HANDLE_VALUE) + return -1; + + size_t res = size; + int retval = 0; + + while (res > 0) { + DWORD written; + if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) { + retval = -1; + ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError()); + break; + } + res -= written; + } + return retval; +} + +const unsigned char *Win32PipeStream::readFully(void *buf, size_t len) +{ + const unsigned char* ret = NULL; + + if (m_pipe == INVALID_HANDLE_VALUE) + return NULL; + + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + size_t res = len; + while (res > 0) { + DWORD readcount = 0; + if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) { + errno = (int)GetLastError(); + return NULL; + } + res -= readcount; + } + return (const unsigned char *)buf; +} + +const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len) +{ + size_t len = *inout_len; + DWORD readcount; + + if (m_pipe == INVALID_HANDLE_VALUE) + return NULL; + + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) { + errno = (int)GetLastError(); + return NULL; + } + + *inout_len = (size_t)readcount; + return (const unsigned char *)buf; +} |