blob: 6b56bb5ffa8e9e8e337dd94814534d912f303c4f [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
28FrameworkListener::FrameworkListener(const char *socketName) :
29 SocketListener(socketName, true) {
30 mCommands = new FrameworkCommandCollection();
Robert Greenwaltdc58e732012-02-07 12:23:14 -080031 errorRate = 0;
32 mCommandCount = 0;
San Mehat168415b2009-05-06 11:14:21 -070033}
34
San Mehatfa644ff2009-05-08 11:15:53 -070035bool FrameworkListener::onDataAvailable(SocketClient *c) {
San Mehatd7680662009-05-12 11:16:59 -070036 char buffer[255];
San Mehat168415b2009-05-06 11:14:21 -070037 int len;
38
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010039 len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
40 if (len < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070041 SLOGE("read() failed (%s)", strerror(errno));
Kenny Rootf31d2ed2010-09-14 09:55:22 -070042 return false;
San Mehatc73a3a52009-06-15 14:06:03 -070043 } else if (!len)
San Mehat168415b2009-05-06 11:14:21 -070044 return false;
San Mehat168415b2009-05-06 11:14:21 -070045
San Mehatd7680662009-05-12 11:16:59 -070046 int offset = 0;
San Mehat168415b2009-05-06 11:14:21 -070047 int i;
48
San Mehat168415b2009-05-06 11:14:21 -070049 for (i = 0; i < len; i++) {
San Mehatc73a3a52009-06-15 14:06:03 -070050 if (buffer[i] == '\0') {
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010051 /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
San Mehatd7680662009-05-12 11:16:59 -070052 dispatchCommand(c, buffer + offset);
53 offset = i + 1;
San Mehat168415b2009-05-06 11:14:21 -070054 }
55 }
56 return true;
57}
58
59void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
60 mCommands->push_back(cmd);
61}
62
San Mehatc73a3a52009-06-15 14:06:03 -070063void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
San Mehatc4a895b2009-06-23 21:10:57 -070064 FrameworkCommandCollection::iterator i;
65 int argc = 0;
San Mehatc73a3a52009-06-15 14:06:03 -070066 char *argv[FrameworkListener::CMD_ARGS_MAX];
San Mehatc4a895b2009-06-23 21:10:57 -070067 char tmp[255];
68 char *p = data;
69 char *q = tmp;
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010070 char *qlimit = tmp + sizeof(tmp) - 1;
San Mehatc4a895b2009-06-23 21:10:57 -070071 bool esc = false;
72 bool quote = false;
73 int k;
Robert Greenwaltdc58e732012-02-07 12:23:14 -080074 bool haveCmdNum = false;
San Mehatfa644ff2009-05-08 11:15:53 -070075
San Mehatc4a895b2009-06-23 21:10:57 -070076 memset(argv, 0, sizeof(argv));
77 memset(tmp, 0, sizeof(tmp));
78 while(*p) {
79 if (*p == '\\') {
80 if (esc) {
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010081 if (q >= qlimit)
82 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -070083 *q++ = '\\';
84 esc = false;
85 } else
86 esc = true;
87 p++;
88 continue;
89 } else if (esc) {
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010090 if (*p == '"') {
91 if (q >= qlimit)
92 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -070093 *q++ = '"';
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010094 } else if (*p == '\\') {
95 if (q >= qlimit)
96 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -070097 *q++ = '\\';
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +010098 } else {
San Mehatc4a895b2009-06-23 21:10:57 -070099 cli->sendMsg(500, "Unsupported escape sequence", false);
100 goto out;
101 }
102 p++;
103 esc = false;
104 continue;
105 }
San Mehatc73a3a52009-06-15 14:06:03 -0700106
San Mehatc4a895b2009-06-23 21:10:57 -0700107 if (*p == '"') {
108 if (quote)
109 quote = false;
110 else
111 quote = true;
112 p++;
113 continue;
114 }
115
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100116 if (q >= qlimit)
117 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700118 *q = *p++;
119 if (!quote && *q == ' ') {
120 *q = '\0';
Robert Greenwaltdc58e732012-02-07 12:23:14 -0800121 if (!haveCmdNum) {
122 cli->setCmdNum(atoi(tmp));
123 haveCmdNum = true;
124 } else {
125 if (argc >= CMD_ARGS_MAX)
126 goto overflow;
127 argv[argc++] = strdup(tmp);
128 }
San Mehatc4a895b2009-06-23 21:10:57 -0700129 memset(tmp, 0, sizeof(tmp));
130 q = tmp;
131 continue;
132 }
133 q++;
San Mehatfa644ff2009-05-08 11:15:53 -0700134 }
135
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100136 *q = '\0';
137 if (argc >= CMD_ARGS_MAX)
138 goto overflow;
San Mehatc4a895b2009-06-23 21:10:57 -0700139 argv[argc++] = strdup(tmp);
140#if 0
141 for (k = 0; k < argc; k++) {
San Mehat7e8529a2010-03-25 09:31:42 -0700142 SLOGD("arg[%d] = '%s'", k, argv[k]);
San Mehatc4a895b2009-06-23 21:10:57 -0700143 }
144#endif
San Mehat168415b2009-05-06 11:14:21 -0700145
San Mehatc4a895b2009-06-23 21:10:57 -0700146 if (quote) {
147 cli->sendMsg(500, "Unclosed quotes error", false);
148 goto out;
149 }
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100150
Robert Greenwaltdc58e732012-02-07 12:23:14 -0800151 if (errorRate && (++mCommandCount % errorRate == 0)) {
152 /* ignore this command - let the timeout handler handle it */
153 SLOGE("Faking a timeout");
154 goto out;
155 }
156
San Mehat168415b2009-05-06 11:14:21 -0700157 for (i = mCommands->begin(); i != mCommands->end(); ++i) {
158 FrameworkCommand *c = *i;
159
San Mehatc73a3a52009-06-15 14:06:03 -0700160 if (!strcmp(argv[0], c->getCommand())) {
161 if (c->runCommand(cli, argc, argv)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700162 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
San Mehat168415b2009-05-06 11:14:21 -0700163 }
San Mehatc4a895b2009-06-23 21:10:57 -0700164 goto out;
San Mehat168415b2009-05-06 11:14:21 -0700165 }
166 }
167
San Mehatd7680662009-05-12 11:16:59 -0700168 cli->sendMsg(500, "Command not recognized", false);
San Mehatc4a895b2009-06-23 21:10:57 -0700169out:
170 int j;
171 for (j = 0; j < argc; j++)
172 free(argv[j]);
San Mehatfa644ff2009-05-08 11:15:53 -0700173 return;
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100174
175overflow:
Nick Kralevich6bbaaa62011-11-18 08:46:54 -0800176 LOG_EVENT_INT(78001, cli->getUid());
David 'Digit' Turnerc6b0def2011-01-17 03:29:04 +0100177 cli->sendMsg(500, "Command too long", false);
178 goto out;
San Mehat168415b2009-05-06 11:14:21 -0700179}