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 "UnixStream.h" 17#include <cutils/sockets.h> 18#include <errno.h> 19#include <stdio.h> 20#include <stdlib.h> 21#include <unistd.h> 22#include <string.h> 23 24#include <netinet/in.h> 25#include <netinet/tcp.h> 26#include <sys/un.h> 27#include <sys/stat.h> 28 29/* Not all systems define PATH_MAX, those who don't generally don't 30 * have a limit on the maximum path size, so use a value that is 31 * large enough for our very limited needs. 32 */ 33#ifndef PATH_MAX 34#define PATH_MAX 128 35#endif 36 37UnixStream::UnixStream(size_t bufSize) : 38 SocketStream(bufSize) 39{ 40} 41 42UnixStream::UnixStream(int sock, size_t bufSize) : 43 SocketStream(sock, bufSize) 44{ 45} 46 47/* Initialize a sockaddr_un with the appropriate values corresponding 48 * to a given 'virtual port'. Returns 0 on success, -1 on error. 49 */ 50static int 51make_unix_path(char *path, size_t pathlen, int port_number) 52{ 53 char tmp[PATH_MAX]; // temp directory 54 int ret = 0; 55 56 // First, create user-specific temp directory if needed 57 const char* user = getenv("USER"); 58 if (user != NULL) { 59 struct stat st; 60 snprintf(tmp, sizeof(tmp), "/tmp/android-%s", user); 61 do { 62 ret = ::lstat(tmp, &st); 63 } while (ret < 0 && errno == EINTR); 64 65 if (ret < 0 && errno == ENOENT) { 66 do { 67 ret = ::mkdir(tmp, 0766); 68 } while (ret < 0 && errno == EINTR); 69 if (ret < 0) { 70 ERR("Could not create temp directory: %s", tmp); 71 user = NULL; // will fall-back to /tmp 72 } 73 } 74 else if (ret < 0) { 75 user = NULL; // will fallback to /tmp 76 } 77 } 78 79 if (user == NULL) { // fallback to /tmp in case of error 80 snprintf(tmp, sizeof(tmp), "/tmp"); 81 } 82 83 // Now, initialize it properly 84 snprintf(path, pathlen, "%s/qemu-gles-%d", tmp, port_number); 85 return 0; 86} 87 88 89int UnixStream::listen(unsigned short port) 90{ 91 char path[PATH_MAX]; 92 93 if (make_unix_path(path, sizeof(path), port) < 0) { 94 return -1; 95 } 96 97 m_sock = socket_local_server(path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); 98 if (!valid()) return int(ERR_INVALID_SOCKET); 99 100 return 0; 101} 102 103SocketStream * UnixStream::accept() 104{ 105 int clientSock = -1; 106 107 while (true) { 108 struct sockaddr_un addr; 109 socklen_t len = sizeof(addr); 110 clientSock = ::accept(m_sock, (sockaddr *)&addr, &len); 111 112 if (clientSock < 0 && errno == EINTR) { 113 continue; 114 } 115 break; 116 } 117 118 UnixStream *clientStream = NULL; 119 120 if (clientSock >= 0) { 121 clientStream = new UnixStream(clientSock, m_bufsize); 122 } 123 return clientStream; 124} 125 126int UnixStream::connect(unsigned short port) 127{ 128 char path[PATH_MAX]; 129 130 if (make_unix_path(path, sizeof(path), port) < 0) 131 return -1; 132 133 m_sock = socket_local_client(path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); 134 if (!valid()) return -1; 135 136 return 0; 137} 138