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