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