1/* 2 * Copyright (C) 2008 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 <errno.h> 17#include <string.h> 18#include <stdlib.h> 19 20#define LOG_TAG "FrameworkListener" 21 22#include <cutils/log.h> 23 24#include <sysutils/FrameworkListener.h> 25#include <sysutils/FrameworkCommand.h> 26#include <sysutils/SocketClient.h> 27 28static const int CMD_BUF_SIZE = 1024; 29 30#define UNUSED __attribute__((unused)) 31 32FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) : 33 SocketListener(socketName, true, withSeq) { 34 init(socketName, withSeq); 35} 36 37FrameworkListener::FrameworkListener(const char *socketName) : 38 SocketListener(socketName, true, false) { 39 init(socketName, false); 40} 41 42FrameworkListener::FrameworkListener(int sock) : 43 SocketListener(sock, true) { 44 init(NULL, false); 45} 46 47void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) { 48 mCommands = new FrameworkCommandCollection(); 49 errorRate = 0; 50 mCommandCount = 0; 51 mWithSeq = withSeq; 52 mSkipToNextNullByte = false; 53} 54 55bool FrameworkListener::onDataAvailable(SocketClient *c) { 56 char buffer[CMD_BUF_SIZE]; 57 int len; 58 59 len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer))); 60 if (len < 0) { 61 SLOGE("read() failed (%s)", strerror(errno)); 62 return false; 63 } else if (!len) { 64 return false; 65 } else if (buffer[len-1] != '\0') { 66 SLOGW("String is not zero-terminated"); 67 android_errorWriteLog(0x534e4554, "29831647"); 68 c->sendMsg(500, "Command too large for buffer", false); 69 mSkipToNextNullByte = true; 70 return false; 71 } 72 73 int offset = 0; 74 int i; 75 76 for (i = 0; i < len; i++) { 77 if (buffer[i] == '\0') { 78 /* IMPORTANT: dispatchCommand() expects a zero-terminated string */ 79 if (mSkipToNextNullByte) { 80 mSkipToNextNullByte = false; 81 } else { 82 dispatchCommand(c, buffer + offset); 83 } 84 offset = i + 1; 85 } 86 } 87 88 mSkipToNextNullByte = false; 89 return true; 90} 91 92void FrameworkListener::registerCmd(FrameworkCommand *cmd) { 93 mCommands->push_back(cmd); 94} 95 96void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { 97 FrameworkCommandCollection::iterator i; 98 int argc = 0; 99 char *argv[FrameworkListener::CMD_ARGS_MAX]; 100 char tmp[CMD_BUF_SIZE]; 101 char *p = data; 102 char *q = tmp; 103 char *qlimit = tmp + sizeof(tmp) - 1; 104 bool esc = false; 105 bool quote = false; 106 bool haveCmdNum = !mWithSeq; 107 108 memset(argv, 0, sizeof(argv)); 109 memset(tmp, 0, sizeof(tmp)); 110 while(*p) { 111 if (*p == '\\') { 112 if (esc) { 113 if (q >= qlimit) 114 goto overflow; 115 *q++ = '\\'; 116 esc = false; 117 } else 118 esc = true; 119 p++; 120 continue; 121 } else if (esc) { 122 if (*p == '"') { 123 if (q >= qlimit) 124 goto overflow; 125 *q++ = '"'; 126 } else if (*p == '\\') { 127 if (q >= qlimit) 128 goto overflow; 129 *q++ = '\\'; 130 } else { 131 cli->sendMsg(500, "Unsupported escape sequence", false); 132 goto out; 133 } 134 p++; 135 esc = false; 136 continue; 137 } 138 139 if (*p == '"') { 140 if (quote) 141 quote = false; 142 else 143 quote = true; 144 p++; 145 continue; 146 } 147 148 if (q >= qlimit) 149 goto overflow; 150 *q = *p++; 151 if (!quote && *q == ' ') { 152 *q = '\0'; 153 if (!haveCmdNum) { 154 char *endptr; 155 int cmdNum = (int)strtol(tmp, &endptr, 0); 156 if (endptr == NULL || *endptr != '\0') { 157 cli->sendMsg(500, "Invalid sequence number", false); 158 goto out; 159 } 160 cli->setCmdNum(cmdNum); 161 haveCmdNum = true; 162 } else { 163 if (argc >= CMD_ARGS_MAX) 164 goto overflow; 165 argv[argc++] = strdup(tmp); 166 } 167 memset(tmp, 0, sizeof(tmp)); 168 q = tmp; 169 continue; 170 } 171 q++; 172 } 173 174 *q = '\0'; 175 if (argc >= CMD_ARGS_MAX) 176 goto overflow; 177 argv[argc++] = strdup(tmp); 178#if 0 179 for (int k = 0; k < argc; k++) { 180 SLOGD("arg[%d] = '%s'", k, argv[k]); 181 } 182#endif 183 184 if (quote) { 185 cli->sendMsg(500, "Unclosed quotes error", false); 186 goto out; 187 } 188 189 if (errorRate && (++mCommandCount % errorRate == 0)) { 190 /* ignore this command - let the timeout handler handle it */ 191 SLOGE("Faking a timeout"); 192 goto out; 193 } 194 195 for (i = mCommands->begin(); i != mCommands->end(); ++i) { 196 FrameworkCommand *c = *i; 197 198 if (!strcmp(argv[0], c->getCommand())) { 199 if (c->runCommand(cli, argc, argv)) { 200 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); 201 } 202 goto out; 203 } 204 } 205 cli->sendMsg(500, "Command not recognized", false); 206out: 207 int j; 208 for (j = 0; j < argc; j++) 209 free(argv[j]); 210 return; 211 212overflow: 213 LOG_EVENT_INT(78001, cli->getUid()); 214 cli->sendMsg(500, "Command too long", false); 215 goto out; 216} 217