The modules here are only built when BUILD_EMULATOR_OPENGL is defined to true in your environment or your BoardConfig.mk (see tools/emulator/opengl/Android.mk) Change-Id: I5f32c35b4452fb5a7b4d5f9fc5870ec1da6032e6
240 lines
7.0 KiB
C++
240 lines
7.0 KiB
C++
/*
|
|
* 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;
|
|
}
|