Because of the way the SDK and Android system images are branched,
host code that goes into the SDK tools can't live in the same
repository as code that goes into the system image. This change keeps
the emugl host code in sdk.git/emulator/opengl while moving the emugl
system code to development.git/tools/emulator/opengl.
A few changes were made beyond simply cloning the directories:
(a) Makefiles were modified to only build the relevant components. Not
doing so would break the build due to having multiple rule
definitions.
(b) Protocol spec files were moved from the guest encoder directories
to the host decoder directories. The decoder must support older
versions of the protocol, but not newer versions, so it makes
sense to keep the latest version of the protocol spec with the
decoder.
(c) Along with that, the encoder is now built from checked in
generated encoder source rather than directly from the protocol
spec. The generated code must be updated manually. This makes it
possible to freeze the system encoder version without freezing the
host decoder version, and also makes it very obvious when a
protocol changes is happening that will require special
backwards-compatibility support in the decoder/renderer.
(d) Host-only and system-only code were removed from the repository
where they aren't used.
(e) README and DESIGN documents were updated to reflect this split.
No actual source code was changed due to the above.
Change-Id: I2c936101ea0405b372750d36ba0f01e84d719c43
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;
|
|
}
|