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