Home | History | Annotate | Download | only in src
      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 
     28 FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
     29                             SocketListener(socketName, true, withSeq) {
     30     init(socketName, withSeq);
     31 }
     32 
     33 FrameworkListener::FrameworkListener(const char *socketName) :
     34                             SocketListener(socketName, true, false) {
     35     init(socketName, false);
     36 }
     37 
     38 void FrameworkListener::init(const char *socketName, bool withSeq) {
     39     mCommands = new FrameworkCommandCollection();
     40     errorRate = 0;
     41     mCommandCount = 0;
     42     mWithSeq = withSeq;
     43 }
     44 
     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 
     69 void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
     70     mCommands->push_back(cmd);
     71 }
     72 
     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