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