1168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat/*
2168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * Copyright (C) 2008 The Android Open Source Project
3168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat *
4168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * you may not use this file except in compliance with the License.
6168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * You may obtain a copy of the License at
7168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat *
8168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat *
10168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * Unless required by applicable law or agreed to in writing, software
11168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * See the License for the specific language governing permissions and
14168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * limitations under the License.
15168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat */
16168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
17168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat#define LOG_TAG "FrameworkListener"
18168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
1966ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn#include <errno.h>
2066ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn#include <stdlib.h>
2166ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn#include <string.h>
22cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#include <unistd.h>
23168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
24cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#include <log/log.h>
25168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat#include <sysutils/FrameworkCommand.h>
2666ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn#include <sysutils/FrameworkListener.h>
27fa644ffe944c01a9b00f8d7676d58394fabee285San Mehat#include <sysutils/SocketClient.h>
28168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
296d358ae44ccfbcd5b89511d142f334b2cc1b67b1Josef Kindbergstatic const int CMD_BUF_SIZE = 1024;
306d358ae44ccfbcd5b89511d142f334b2cc1b67b1Josef Kindberg
31e16baef4d2f59c0b5f78e66c838d6c5e7d9b7363Mark Salyzyn#define UNUSED __attribute__((unused))
32e16baef4d2f59c0b5f78e66c838d6c5e7d9b7363Mark Salyzyn
338702bb17f40022e970e8acd40b348d074e39afc7Robert GreenwaltFrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
348702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                            SocketListener(socketName, true, withSeq) {
358702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    init(socketName, withSeq);
368702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt}
378702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt
38168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatFrameworkListener::FrameworkListener(const char *socketName) :
398702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                            SocketListener(socketName, true, false) {
408702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    init(socketName, false);
418702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt}
428702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt
43dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark SalyzynFrameworkListener::FrameworkListener(int sock) :
44dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn                            SocketListener(sock, true) {
45dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn    init(NULL, false);
46dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn}
47dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn
48e16baef4d2f59c0b5f78e66c838d6c5e7d9b7363Mark Salyzynvoid FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
49168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    mCommands = new FrameworkCommandCollection();
508702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    errorRate = 0;
518702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    mCommandCount = 0;
528702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    mWithSeq = withSeq;
53470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien    mSkipToNextNullByte = false;
54168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
55168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
56fa644ffe944c01a9b00f8d7676d58394fabee285San Mehatbool FrameworkListener::onDataAvailable(SocketClient *c) {
576d358ae44ccfbcd5b89511d142f334b2cc1b67b1Josef Kindberg    char buffer[CMD_BUF_SIZE];
58168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    int len;
59168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
60c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
61c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    if (len < 0) {
627e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGE("read() failed (%s)", strerror(errno));
63f31d2ed1fd3a39a92bccc12eb66728594290ef3bKenny Root        return false;
64470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien    } else if (!len) {
65168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        return false;
66470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien    } else if (buffer[len-1] != '\0') {
676d358ae44ccfbcd5b89511d142f334b2cc1b67b1Josef Kindberg        SLOGW("String is not zero-terminated");
68470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien        android_errorWriteLog(0x534e4554, "29831647");
69470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien        c->sendMsg(500, "Command too large for buffer", false);
70470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien        mSkipToNextNullByte = true;
71d3c86412adfb3b782ee8b4a70b8c25be5d35138aNIEJuhu        return true;
72470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien    }
73168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
74d768066ef54270a0d3ccfccd50ae8238db5a2cddSan Mehat    int offset = 0;
75168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    int i;
76168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
77168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    for (i = 0; i < len; i++) {
78c73a3a5771a2d29d1bae666bfde12f751d66fc96San Mehat        if (buffer[i] == '\0') {
79c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
80470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien            if (mSkipToNextNullByte) {
81470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien                mSkipToNextNullByte = false;
82470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien            } else {
83470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien                dispatchCommand(c, buffer + offset);
84470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien            }
85d768066ef54270a0d3ccfccd50ae8238db5a2cddSan Mehat            offset = i + 1;
86168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        }
87168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    }
886d358ae44ccfbcd5b89511d142f334b2cc1b67b1Josef Kindberg
89470484d2a25ad432190a01d1c763b4b36db33c7eConnor O'Brien    mSkipToNextNullByte = false;
90168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    return true;
91168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
92168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
93168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatvoid FrameworkListener::registerCmd(FrameworkCommand *cmd) {
94168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    mCommands->push_back(cmd);
95168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
96168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
97c73a3a5771a2d29d1bae666bfde12f751d66fc96San Mehatvoid FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
98c4a895b7094461c98101924cf096680bfb7856f1San Mehat    FrameworkCommandCollection::iterator i;
99c4a895b7094461c98101924cf096680bfb7856f1San Mehat    int argc = 0;
100c73a3a5771a2d29d1bae666bfde12f751d66fc96San Mehat    char *argv[FrameworkListener::CMD_ARGS_MAX];
1016d358ae44ccfbcd5b89511d142f334b2cc1b67b1Josef Kindberg    char tmp[CMD_BUF_SIZE];
102c4a895b7094461c98101924cf096680bfb7856f1San Mehat    char *p = data;
103c4a895b7094461c98101924cf096680bfb7856f1San Mehat    char *q = tmp;
104c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    char *qlimit = tmp + sizeof(tmp) - 1;
105c4a895b7094461c98101924cf096680bfb7856f1San Mehat    bool esc = false;
106c4a895b7094461c98101924cf096680bfb7856f1San Mehat    bool quote = false;
1078702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    bool haveCmdNum = !mWithSeq;
108c4a895b7094461c98101924cf096680bfb7856f1San Mehat
109c4a895b7094461c98101924cf096680bfb7856f1San Mehat    memset(argv, 0, sizeof(argv));
110c4a895b7094461c98101924cf096680bfb7856f1San Mehat    memset(tmp, 0, sizeof(tmp));
111c4a895b7094461c98101924cf096680bfb7856f1San Mehat    while(*p) {
112c4a895b7094461c98101924cf096680bfb7856f1San Mehat        if (*p == '\\') {
113c4a895b7094461c98101924cf096680bfb7856f1San Mehat            if (esc) {
114c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner                if (q >= qlimit)
115c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner                    goto overflow;
116c4a895b7094461c98101924cf096680bfb7856f1San Mehat                *q++ = '\\';
117c4a895b7094461c98101924cf096680bfb7856f1San Mehat                esc = false;
118c4a895b7094461c98101924cf096680bfb7856f1San Mehat            } else
119c4a895b7094461c98101924cf096680bfb7856f1San Mehat                esc = true;
120c4a895b7094461c98101924cf096680bfb7856f1San Mehat            p++;
121c4a895b7094461c98101924cf096680bfb7856f1San Mehat            continue;
122c4a895b7094461c98101924cf096680bfb7856f1San Mehat        } else if (esc) {
123c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner            if (*p == '"') {
124c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner                if (q >= qlimit)
125c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner                    goto overflow;
126c4a895b7094461c98101924cf096680bfb7856f1San Mehat                *q++ = '"';
127c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner            } else if (*p == '\\') {
128c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner                if (q >= qlimit)
129c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner                    goto overflow;
130c4a895b7094461c98101924cf096680bfb7856f1San Mehat                *q++ = '\\';
131c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner            } else {
132c4a895b7094461c98101924cf096680bfb7856f1San Mehat                cli->sendMsg(500, "Unsupported escape sequence", false);
133c4a895b7094461c98101924cf096680bfb7856f1San Mehat                goto out;
134c4a895b7094461c98101924cf096680bfb7856f1San Mehat            }
135c4a895b7094461c98101924cf096680bfb7856f1San Mehat            p++;
136c4a895b7094461c98101924cf096680bfb7856f1San Mehat            esc = false;
137c4a895b7094461c98101924cf096680bfb7856f1San Mehat            continue;
138c4a895b7094461c98101924cf096680bfb7856f1San Mehat        }
139c4a895b7094461c98101924cf096680bfb7856f1San Mehat
140c4a895b7094461c98101924cf096680bfb7856f1San Mehat        if (*p == '"') {
141c4a895b7094461c98101924cf096680bfb7856f1San Mehat            if (quote)
142c4a895b7094461c98101924cf096680bfb7856f1San Mehat                quote = false;
143c4a895b7094461c98101924cf096680bfb7856f1San Mehat            else
144c4a895b7094461c98101924cf096680bfb7856f1San Mehat                quote = true;
145c4a895b7094461c98101924cf096680bfb7856f1San Mehat            p++;
146c4a895b7094461c98101924cf096680bfb7856f1San Mehat            continue;
147c4a895b7094461c98101924cf096680bfb7856f1San Mehat        }
148c73a3a5771a2d29d1bae666bfde12f751d66fc96San Mehat
149c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner        if (q >= qlimit)
150c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner            goto overflow;
151c4a895b7094461c98101924cf096680bfb7856f1San Mehat        *q = *p++;
152c4a895b7094461c98101924cf096680bfb7856f1San Mehat        if (!quote && *q == ' ') {
153c4a895b7094461c98101924cf096680bfb7856f1San Mehat            *q = '\0';
1548702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt            if (!haveCmdNum) {
1558702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                char *endptr;
1568702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                int cmdNum = (int)strtol(tmp, &endptr, 0);
1578702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                if (endptr == NULL || *endptr != '\0') {
1588702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                    cli->sendMsg(500, "Invalid sequence number", false);
1598702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                    goto out;
1608702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                }
1618702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                cli->setCmdNum(cmdNum);
1628702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                haveCmdNum = true;
1638702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt            } else {
1648702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                if (argc >= CMD_ARGS_MAX)
1658702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                    goto overflow;
1668702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt                argv[argc++] = strdup(tmp);
1678702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt            }
168c4a895b7094461c98101924cf096680bfb7856f1San Mehat            memset(tmp, 0, sizeof(tmp));
169c4a895b7094461c98101924cf096680bfb7856f1San Mehat            q = tmp;
170c4a895b7094461c98101924cf096680bfb7856f1San Mehat            continue;
171c4a895b7094461c98101924cf096680bfb7856f1San Mehat        }
172c4a895b7094461c98101924cf096680bfb7856f1San Mehat        q++;
173fa644ffe944c01a9b00f8d7676d58394fabee285San Mehat    }
174fa644ffe944c01a9b00f8d7676d58394fabee285San Mehat
175c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    *q = '\0';
176c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    if (argc >= CMD_ARGS_MAX)
177c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner        goto overflow;
178c4a895b7094461c98101924cf096680bfb7856f1San Mehat    argv[argc++] = strdup(tmp);
179c4a895b7094461c98101924cf096680bfb7856f1San Mehat#if 0
1809418fd1821d5f31e6004a6f70cb14f59735dc589Mark Salyzyn    for (int k = 0; k < argc; k++) {
1817e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGD("arg[%d] = '%s'", k, argv[k]);
182c4a895b7094461c98101924cf096680bfb7856f1San Mehat    }
183c4a895b7094461c98101924cf096680bfb7856f1San Mehat#endif
184168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
185c4a895b7094461c98101924cf096680bfb7856f1San Mehat    if (quote) {
186c4a895b7094461c98101924cf096680bfb7856f1San Mehat        cli->sendMsg(500, "Unclosed quotes error", false);
187c4a895b7094461c98101924cf096680bfb7856f1San Mehat        goto out;
188c4a895b7094461c98101924cf096680bfb7856f1San Mehat    }
189c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner
1908702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    if (errorRate && (++mCommandCount % errorRate == 0)) {
1918702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt        /* ignore this command - let the timeout handler handle it */
1928702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt        SLOGE("Faking a timeout");
1938702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt        goto out;
1948702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt    }
1958702bb17f40022e970e8acd40b348d074e39afc7Robert Greenwalt
196168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
197168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        FrameworkCommand *c = *i;
198168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
199c73a3a5771a2d29d1bae666bfde12f751d66fc96San Mehat        if (!strcmp(argv[0], c->getCommand())) {
200c73a3a5771a2d29d1bae666bfde12f751d66fc96San Mehat            if (c->runCommand(cli, argc, argv)) {
2017e8529a8b528fd30586aa037f15a31b29582c537San Mehat                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
202168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat            }
203c4a895b7094461c98101924cf096680bfb7856f1San Mehat            goto out;
204168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        }
205168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    }
206d768066ef54270a0d3ccfccd50ae8238db5a2cddSan Mehat    cli->sendMsg(500, "Command not recognized", false);
207c4a895b7094461c98101924cf096680bfb7856f1San Mehatout:
208c4a895b7094461c98101924cf096680bfb7856f1San Mehat    int j;
209c4a895b7094461c98101924cf096680bfb7856f1San Mehat    for (j = 0; j < argc; j++)
210c4a895b7094461c98101924cf096680bfb7856f1San Mehat        free(argv[j]);
211fa644ffe944c01a9b00f8d7676d58394fabee285San Mehat    return;
212c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner
213c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turneroverflow:
214c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    cli->sendMsg(500, "Command too long", false);
215c6b0def5f039dc3bbe1d4b7dc1666c24316eb020David 'Digit' Turner    goto out;
216168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
217