1 /* 2 * Copyright 2018, 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 17 #include "commander.h" 18 19 #include "commands/command.h" 20 #include "log.h" 21 22 #include <errno.h> 23 #pragma clang diagnostic push 24 #pragma clang diagnostic ignored "-Wunused-function" 25 #include <qemu_pipe.h> 26 #pragma clang diagnostic pop 27 #include <string.h> 28 #include <sys/socket.h> 29 #include <sys/types.h> 30 31 static const char kQemuPipeName[] = "qemud:network"; 32 33 // How much space to use for each command received 34 static const size_t kReceiveSpace = 1024; 35 // The maximum amount of bytes to keep in the receive buffer for a single 36 // command before dropping data. 37 static const size_t kMaxReceiveBufferSize = 65536; 38 39 Commander::Commander() : mPipeFd(-1) { 40 } 41 42 Commander::~Commander() { 43 closePipe(); 44 } 45 46 Result Commander::init() { 47 if (mPipeFd != -1) { 48 return Result::error("Commander already initialized"); 49 } 50 51 openPipe(); 52 53 return Result::success(); 54 } 55 56 void Commander::registerCommand(const char* commandStr, Command* command) { 57 mCommands[commandStr] = command; 58 } 59 60 void Commander::getPollData(std::vector<pollfd>* fds) const { 61 if (mPipeFd != -1) { 62 fds->push_back(pollfd{mPipeFd, POLLIN, 0}); 63 } 64 } 65 66 Pollable::Timestamp Commander::getTimeout() const { 67 return mDeadline; 68 } 69 70 bool Commander::onReadAvailable(int /*fd*/, int* /*status*/) { 71 size_t offset = mReceiveBuffer.size(); 72 mReceiveBuffer.resize(offset + kReceiveSpace); 73 if (mReceiveBuffer.size() > kMaxReceiveBufferSize) { 74 // We have buffered too much data, this should never happen but as a 75 // seurity measure let's just drop everything we have and keep 76 // receiving. Maybe the situation will improve. 77 mReceiveBuffer.resize(kReceiveSpace); 78 offset = 0; 79 } 80 while (true) { 81 int status = ::read(mPipeFd, &mReceiveBuffer[offset], kReceiveSpace); 82 83 if (status < 0) { 84 if (errno == EINTR) { 85 // We got an interrupt, try again 86 continue; 87 } 88 LOGE("Commander failed to receive on pipe: %s", strerror(errno)); 89 // Don't exit the looper because of this, keep trying 90 return true; 91 } 92 size_t length = static_cast<size_t>(status); 93 mReceiveBuffer.resize(offset + length); 94 95 while (true) { 96 auto endline = std::find(mReceiveBuffer.begin(), 97 mReceiveBuffer.end(), 98 '\n'); 99 if (endline == mReceiveBuffer.end()) { 100 // No endline in sight, keep waiting and buffering 101 return true; 102 } 103 104 *endline = '\0'; 105 106 char* args = ::strchr(mReceiveBuffer.data(), ' '); 107 if (args) { 108 *args++ = '\0'; 109 } 110 auto command = mCommands.find(mReceiveBuffer.data()); 111 112 if (command != mCommands.end()) { 113 command->second->onCommand(mReceiveBuffer.data(), args); 114 } 115 // Now that we have processed this line let's remove it from the 116 // receive buffer 117 ++endline; 118 if (endline == mReceiveBuffer.end()) { 119 mReceiveBuffer.clear(); 120 // There can be nothing left, just return 121 return true; 122 } else { 123 mReceiveBuffer.erase(mReceiveBuffer.begin(), endline + 1); 124 // There may be another line in there so keep looping and look 125 // for more 126 } 127 } 128 return true; 129 } 130 } 131 132 bool Commander::onClose(int /*fd*/, int* /*status*/) { 133 // Pipe was closed from the other end, close it on our side and re-open 134 closePipe(); 135 openPipe(); 136 return true; 137 } 138 139 bool Commander::onTimeout(int* /*status*/) { 140 if (mPipeFd == -1) { 141 openPipe(); 142 } 143 return true; 144 } 145 146 void Commander::openPipe() { 147 mPipeFd = qemu_pipe_open(kQemuPipeName); 148 if (mPipeFd == -1) { 149 LOGE("Failed to open QEMU pipe '%s': %s", 150 kQemuPipeName, 151 strerror(errno)); 152 // Try again in the future 153 mDeadline = Pollable::Clock::now() + std::chrono::minutes(1); 154 } else { 155 mDeadline = Pollable::Timestamp::max(); 156 } 157 } 158 159 void Commander::closePipe() { 160 if (mPipeFd != -1) { 161 ::close(mPipeFd); 162 mPipeFd = -1; 163 } 164 } 165