blob: a5ffda230d9a560a28c894056f7818fd4542c809 [file] [log] [blame]
San Mehat168415b2009-05-06 11:14:21 -07001/*
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>
San Mehat3d407292009-05-07 08:49:30 -070017#include <string.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080018#include <stdlib.h>
San Mehat168415b2009-05-06 11:14:21 -070019
20#define LOG_TAG "FrameworkListener"
21
22#include <cutils/log.h>
23
24#include <sysutils/FrameworkListener.h>
25#include <sysutils/FrameworkCommand.h>
San Mehatfa644ff2009-05-08 11:15:53 -070026#include <sysutils/SocketClient.h>
San Mehat168415b2009-05-06 11:14:21 -070027
Josef Kindberg6d358ae2011-02-23 12:40:44 +010028static const int CMD_BUF_SIZE = 1024;
29
Mark Salyzyn696f2672013-11-22 07:47:35 -080030#define UNUSED __attribute__((unused))
31
Robert Greenwalt8702bb12012-02-07 12:23:14 -080032FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
33 SocketListener(socketName, true, withSeq) {
34 init(socketName, withSeq);
35}
36
San Mehat168415b2009-05-06 11:14:21 -070037FrameworkListener::FrameworkListener(const char *socketName) :
Robert Greenwalt8702bb12012-02-07 12:23:14 -080038 SocketListener(socketName, true, false) {
39 init(socketName, false);
40}
41
Mark Salyzyn696f2672013-11-22 07:47:35 -080042void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
San Mehat168415b2009-05-06 11:14:21 -070043 mCommands = new FrameworkCommandCollection();
Robert Greenwalt8702bb12012-02-07 12:23:14 -080044 errorRate = 0;
45 mCommandCount = 0;
46 mWithSeq = withSeq;
San Mehat168415b2009-05-06 11:14:21 -070047}
48
San Mehatfa644ff2009-05-08 11:15:53 -070049bool FrameworkListener::onDataAvailable(SocketClient *c) {
Josef Kindberg6d358ae2011-02-23 12:40:44 +010050 char buffer[CMD_BUF_SIZE];
San Mehat168415b2009-05-06 11:14:21 -070051 int len;
52
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010053 len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
54 if (len < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070055 SLOGE("read() failed (%s)", strerror(errno));
Kenny Rootf31d2ed2010-09-14 09:55:22 -070056 return false;
San Mehatc73a3a52009-06-15 14:06:03 -070057 } else if (!len)
San Mehat168415b2009-05-06 11:14:21 -070058 return false;
Josef Kindberg6d358ae2011-02-23 12:40:44 +010059 if(buffer[len-1] != '\0')
60 SLOGW("String is not zero-terminated");
San Mehat168415b2009-05-06 11:14:21 -070061
San Mehatd7680662009-05-12 11:16:59 -070062 int offset = 0;
San Mehat168415b2009-05-06 11:14:21 -070063 int i;
64
San Mehat168415b2009-05-06 11:14:21 -070065 for (i = 0; i < len; i++) {
San Mehatc73a3a52009-06-15 14:06:03 -070066 if (buffer[i] == '\0') {
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010067 /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
San Mehatd7680662009-05-12 11:16:59 -070068 dispatchCommand(c, buffer + offset);
69 offset = i + 1;
San Mehat168415b2009-05-06 11:14:21 -070070 }
71 }
Josef Kindberg6d358ae2011-02-23 12:40:44 +010072
San Mehat168415b2009-05-06 11:14:21 -070073 return true;
74}
75
76void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
77 mCommands->push_back(cmd);
78}
79
San Mehatc73a3a52009-06-15 14:06:03 -070080void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
San Mehatc4a895b2009-06-23 21:10:57 -070081 FrameworkCommandCollection::iterator i;
82 int argc = 0;
San Mehatc73a3a52009-06-15 14:06:03 -070083 char *argv[FrameworkListener::CMD_ARGS_MAX];
Josef Kindberg6d358ae2011-02-23 12:40:44 +010084 char tmp[CMD_BUF_SIZE];
San Mehatc4a895b2009-06-23 21:10:57 -070085 char *p = data;
86 char *q = tmp;
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010087 char *qlimit = tmp + sizeof(tmp) - 1;
San Mehatc4a895b2009-06-23 21:10:57 -070088 bool esc = false;
89 bool quote = false;
90 int k;
Robert Greenwalt8702bb12012-02-07 12:23:14 -080091 bool haveCmdNum = !mWithSeq;
San Mehatfa644ff2009-05-08 11:15:53 -070092
San Mehatc4a895b2009-06-23 21:10:57 -070093 memset(argv, 0, sizeof(argv));
94 memset(tmp, 0, sizeof(tmp));
95 while(*p) {
96 if (*p == '\\') {
97 if (esc) {
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010098 if (q >= qlimit)
99 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700100 *q++ = '\\';
101 esc = false;
102 } else
103 esc = true;
104 p++;
105 continue;
106 } else if (esc) {
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100107 if (*p == '"') {
108 if (q >= qlimit)
109 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700110 *q++ = '"';
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100111 } else if (*p == '\\') {
112 if (q >= qlimit)
113 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700114 *q++ = '\\';
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100115 } else {
San Mehatc4a895b2009-06-23 21:10:57 -0700116 cli->sendMsg(500, "Unsupported escape sequence", false);
117 goto out;
118 }
119 p++;
120 esc = false;
121 continue;
122 }
San Mehatc73a3a52009-06-15 14:06:03 -0700123
San Mehatc4a895b2009-06-23 21:10:57 -0700124 if (*p == '"') {
125 if (quote)
126 quote = false;
127 else
128 quote = true;
129 p++;
130 continue;
131 }
132
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100133 if (q >= qlimit)
134 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700135 *q = *p++;
136 if (!quote && *q == ' ') {
137 *q = '\0';
Robert Greenwalt8702bb12012-02-07 12:23:14 -0800138 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 }
San Mehatc4a895b2009-06-23 21:10:57 -0700152 memset(tmp, 0, sizeof(tmp));
153 q = tmp;
154 continue;
155 }
156 q++;
San Mehatfa644ff2009-05-08 11:15:53 -0700157 }
158
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100159 *q = '\0';
160 if (argc >= CMD_ARGS_MAX)
161 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700162 argv[argc++] = strdup(tmp);
163#if 0
164 for (k = 0; k < argc; k++) {
San Mehat7e8529a2010-03-25 09:31:42 -0700165 SLOGD("arg[%d] = '%s'", k, argv[k]);
San Mehatc4a895b2009-06-23 21:10:57 -0700166 }
167#endif
San Mehat168415b2009-05-06 11:14:21 -0700168
San Mehatc4a895b2009-06-23 21:10:57 -0700169 if (quote) {
170 cli->sendMsg(500, "Unclosed quotes error", false);
171 goto out;
172 }
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100173
Robert Greenwalt8702bb12012-02-07 12:23:14 -0800174 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
San Mehat168415b2009-05-06 11:14:21 -0700180 for (i = mCommands->begin(); i != mCommands->end(); ++i) {
181 FrameworkCommand *c = *i;
182
San Mehatc73a3a52009-06-15 14:06:03 -0700183 if (!strcmp(argv[0], c->getCommand())) {
184 if (c->runCommand(cli, argc, argv)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700185 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
San Mehat168415b2009-05-06 11:14:21 -0700186 }
San Mehatc4a895b2009-06-23 21:10:57 -0700187 goto out;
San Mehat168415b2009-05-06 11:14:21 -0700188 }
189 }
San Mehatd7680662009-05-12 11:16:59 -0700190 cli->sendMsg(500, "Command not recognized", false);
San Mehatc4a895b2009-06-23 21:10:57 -0700191out:
192 int j;
193 for (j = 0; j < argc; j++)
194 free(argv[j]);
San Mehatfa644ff2009-05-08 11:15:53 -0700195 return;
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100196
197overflow:
Nick Kralevich6bbaaa62011-11-18 08:46:54 -0800198 LOG_EVENT_INT(78001, cli->getUid());
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100199 cli->sendMsg(500, "Command too long", false);
200 goto out;
San Mehat168415b2009-05-06 11:14:21 -0700201}