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