blob: 2996d32c83b0fa9bc33317c4d4aa547124cbe55a [file] [log] [blame]
/*
* Copyright 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 <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <cutils/log.h>
#include <private/android_filesystem_config.h>
#include "gltrace_transport.h"
namespace android {
namespace gltrace {
int acceptClientConnection(char *sockname) {
int serverSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
if (serverSocket < 0) {
ALOGE("Error (%d) while creating socket. Check if app has network permissions.",
serverSocket);
return -1;
}
struct sockaddr_un server, client;
memset(&server, 0, sizeof server);
server.sun_family = AF_UNIX;
// the first byte of sun_path should be '\0' for abstract namespace
strcpy(server.sun_path + 1, sockname);
// note that sockaddr_len should be set to the exact size of the buffer that is used.
socklen_t sockaddr_len = sizeof(server.sun_family) + strlen(sockname) + 1;
if (bind(serverSocket, (struct sockaddr *) &server, sockaddr_len) < 0) {
close(serverSocket);
ALOGE("Failed to bind the server socket");
return -1;
}
if (listen(serverSocket, 1) < 0) {
close(serverSocket);
ALOGE("Failed to listen on server socket");
return -1;
}
ALOGD("gltrace::waitForClientConnection: server listening @ path %s", sockname);
int clientSocket = accept(serverSocket, (struct sockaddr *)&client, &sockaddr_len);
if (clientSocket < 0) {
close(serverSocket);
ALOGE("Failed to accept client connection");
return -1;
}
struct ucred cr;
socklen_t cr_len = sizeof(cr);
if (getsockopt(clientSocket, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) != 0) {
ALOGE("Error obtaining credentials of peer");
return -1;
}
// Only accept connects from the shell (adb forward comes to us as shell user),
// or the root user.
if (cr.uid != AID_SHELL && cr.uid != AID_ROOT) {
ALOGE("Unknown peer type (%d), expected shell to be the peer", cr.uid);
return -1;
}
ALOGD("gltrace::waitForClientConnection: client connected.");
// do not accept any more incoming connections
close(serverSocket);
return clientSocket;
}
TCPStream::TCPStream(int socket) {
mSocket = socket;
pthread_mutex_init(&mSocketWriteMutex, NULL);
}
TCPStream::~TCPStream() {
pthread_mutex_destroy(&mSocketWriteMutex);
}
void TCPStream::closeStream() {
if (mSocket > 0) {
close(mSocket);
mSocket = 0;
}
}
int TCPStream::send(void *buf, size_t len) {
if (mSocket <= 0) {
return -1;
}
pthread_mutex_lock(&mSocketWriteMutex);
int n = write(mSocket, buf, len);
pthread_mutex_unlock(&mSocketWriteMutex);
return n;
}
int TCPStream::receive(void *data, size_t len) {
if (mSocket <= 0) {
return -1;
}
size_t totalRead = 0;
while (totalRead < len) {
int n = read(mSocket, (uint8_t*)data + totalRead, len - totalRead);
if (n < 0) {
ALOGE("Error receiving data from stream: %d", errno);
return -1;
}
totalRead += n;
}
return 0;
}
BufferedOutputStream::BufferedOutputStream(TCPStream *stream, size_t bufferSize) {
mStream = stream;
mBufferSize = bufferSize;
mStringBuffer = "";
mStringBuffer.reserve(bufferSize);
}
int BufferedOutputStream::flush() {
if (mStringBuffer.size() == 0) {
return 0;
}
int n = mStream->send((void *)mStringBuffer.data(), mStringBuffer.size());
mStringBuffer.clear();
return n;
}
void BufferedOutputStream::enqueueMessage(GLMessage *msg) {
const uint32_t len = msg->ByteSize();
mStringBuffer.append((const char *)&len, sizeof(len)); // append header
msg->AppendToString(&mStringBuffer); // append message
}
int BufferedOutputStream::send(GLMessage *msg) {
enqueueMessage(msg);
if (mStringBuffer.size() > mBufferSize) {
return flush();
}
return 0;
}
}; // namespace gltrace
}; // namespace android