Example #1
0
struct filter *convert_specifier(struct specifier_s *r,
                                 struct filtergen_opts *o) {
  struct filter *res = NULL;
  eprint("converting specifier\n");

  if (r->compound) {
    eprint("converting compound specifier\n");
    res = convert_compound_specifier(r->compound, o);
  } else if (r->direction) {
    res = convert_direction(r->direction, o);
  } else if (r->target) {
    enum filtertype type;

    eprint("converting target specifier\n");

    switch (r->target->type) {
    case TOK_ACCEPT:
      type = T_ACCEPT;
      break;
    case TOK_REJECT:
      type = T_REJECT;
      break;
    case TOK_DROP:
      type = DROP;
      break;
    case TOK_MASQ:
      type = MASQ;
      break;
    case TOK_PROXY:
      type = REDIRECT;
      break;
    case TOK_REDIRECT:
      type = REDIRECT;
      break;
    default:
      filter_error(r->pos, "incorrect target type encountered");
      type = YYEOF;
      break;
    }
    res = new_filter_target(type, r->pos);
  } else if (r->host) {
    res = convert_host_specifier(r->host, o);
  } else if (r->protocol) {
    res = convert_protocol_specifier(r->protocol, o);
  } else if (r->port) {
    res = convert_port_specifier(r->port, o);
  } else if (r->icmptype) {
    res = convert_icmptype_specifier(r->icmptype, o);
  } else if (r->option) {
    res = convert_option_specifier(r->option);
  } else if (r->chaingroup) {
    res = convert_chaingroup_specifier(r->chaingroup, o);
  } else {
    filter_error(r->pos, "no specifiers");
  }
  if (res)
    res->pos = r->pos;
  free(r);
  return res;
}
static void
generate_result_dispatcher_method(const method_type* method,
        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
{
    arg_type* arg;
    Method* dispatchMethod;
    Variable* dispatchParam;
    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);

    Variable* classLoader = NULL;
    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));

    // The callback method itself
    MethodCall* realCall = new MethodCall(
            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
            results_method_name(method->name.data));

    // The return value
    {
        Type* t = NAMES.Search(method->type.type.data);
        if (t != VOID_TYPE) {
            Variable* rv = new Variable(t, "rv");
            dispatchMethod->statements->Add(new VariableDeclaration(rv));
            generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
                    resultData, &classLoader);
            realCall->arguments.push_back(rv);
        }
    }

    VariableFactory stubArgs("arg");
    arg = method->args;
    while (arg != NULL) {
        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            // Unmarshall the results
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = stubArgs.Get(t);
            dispatchMethod->statements->Add(new VariableDeclaration(v));

            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
                    resultData, &classLoader);

            // Add the argument to the callback
            realCall->arguments.push_back(v);
        }
        arg = arg->next;
    }

    // Call the callback method
    IfStatement* ifst = new IfStatement;
        ifst->expression = new Comparison(new FieldVariable(THIS_VALUE, "callback"), "!=", NULL_VALUE);
    dispatchMethod->statements->Add(ifst);
    ifst->statements->Add(realCall);
}
// =================================================
static Type*
generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
{
    arg_type* arg;

    string resultsMethodName = results_method_name(method->name.data);
    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
            Type::GENERATED, false, false, false);

    if (!method->oneway) {
        Class* resultsClass = new Class;
            resultsClass->modifiers = STATIC | PUBLIC;
            resultsClass->what = Class::INTERFACE;
            resultsClass->type = resultsInterfaceType;

        Method* resultMethod = new Method;
            resultMethod->comment = gather_comments(method->comments_token->extra);
            resultMethod->modifiers = PUBLIC;
            resultMethod->returnType = VOID_TYPE;
            resultMethod->returnTypeDimension = 0;
            resultMethod->name = resultsMethodName;
        if (0 != strcmp("void", method->type.type.data)) {
            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
                        "_result", method->type.dimension));
        }
        arg = method->args;
        while (arg != NULL) {
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                resultMethod->parameters.push_back(new Variable(
                                    NAMES.Search(arg->type.type.data), arg->name.data,
                                    arg->type.dimension));
            }
            arg = arg->next;
        }
        resultsClass->elements.push_back(resultMethod);

        if (resultMethod->parameters.size() > 0) {
            proxyClass->elements.push_back(resultsClass);
            return resultsInterfaceType;
        } 
    }
    //delete resultsInterfaceType;
    return NULL;
}
static void
generate_method(const method_type* method, Class* interface,
                    StubClass* stubClass, ProxyClass* proxyClass, int index)
{
    arg_type* arg;
    int i;
    bool hasOutParams = false;

    const bool oneway = proxyClass->mOneWay || method->oneway;

    // == the TRANSACT_ constant =============================================
    string transactCodeName = "TRANSACTION_";
    transactCodeName += method->name.data;

    //char transactCodeValue[60];
    //sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);

    //Field* transactCode = new Field(STATIC | FINAL,
    //                        new Variable(INT_TYPE, transactCodeName));
    //transactCode->value = transactCodeValue;
    //interface->elements.push_back(transactCode);

    if (interface->methodEnum == 0) interface->methodEnum = new Enum();
    EnumItem* item = new EnumItem();
    item->name = transactCodeName;
    if (interface->methodEnum->items.size() == 0) item->value = "IBinder::FIRST_CALL_TRANSACTION";
    else item->value = "";
    interface->methodEnum->items.push_back(item);
    interface->declareMetaInterfaceName = string(interface->type->Name().c_str() + 1);
    interface->implementMetaInterfaceName = string(interface->type->Name().c_str() + 1);

    // +JDN
    //interface->implementMetaInterfaceDesc = interface->type->CPPQualifiedName();
    interface->implementMetaInterfaceDesc = interface->type->QualifiedName();
    // -JDN

    // == the declaration in the interface ===================================
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = VIRTUAL;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;

    arg = method->args;
    while (arg != NULL) {
        Type* vType = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(
                    vType, arg->name.data,
                    arg->type.dimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(vType);
        if (userDataType != NULL) {
            v->modifiers = POINTER;
        }
        decl->parameters.push_back(v);
        arg = arg->next;
    }

    // No exception in C++
    //decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);

    interface->elements.push_back(decl);

    // == the stub method ====================================================

    Case* c = new Case(transactCodeName);

    Variable* thisVar = new Variable(interface->type, "this");
    thisVar->modifiers = POINTER;
    MethodCall* realCall = new MethodCall(thisVar/*THIS_VALUE*/, method->name.data);

    // interface token validation is the very first thing we do

    string getDescriptor = interface->type->Name() + string("::getInterfaceDescriptor()");

    // +JDN Don t do checkInterface + enforceInterface it broke serialization
    // c->statements->Add(new MethodCall(stubClass->transact_data,
    //        "enforceInterface", 1, new LiteralExpression(getDescriptor/*"DESCRIPTOR"*/)));
    // -JDN

    // args
    Variable* cl = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(t);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(t);
        if (userDataType != NULL) v->modifiers |= POINTER;
        else if (interfaceType != NULL) v->modifiers |= STRONG_POINTER;
        //if (userDataType != NULL) v->modifiers |= CALL_POINTER;
        v->dimension = arg->type.dimension;

        c->statements->Add(new VariableDeclaration(v));

        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_parcel(t, c->statements, v,
                    stubClass->transact_data, &cl);
        } else {
            if (arg->type.dimension == 0) {
                c->statements->Add(new Assignment(v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, c->statements, v,
                        stubClass->transact_data);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // the real call
    Variable* _result = NULL;
    if (0 == strcmp(method->type.type.data, "void")) {
        c->statements->Add(realCall);

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }
    } else {
        _result = new Variable(decl->returnType, "_result",
                                decl->returnTypeDimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(decl->returnType);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(decl->returnType);
        if (userDataType != NULL) _result->modifiers = POINTER;
        else if (interfaceType != NULL) _result->modifiers = STRONG_POINTER;
        c->statements->Add(new VariableDeclaration(_result, realCall));

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }

        // marshall the return value
        generate_write_to_parcel(decl->returnType, c->statements, _result,
                                    stubClass->transact_reply,
                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
    }

    // out parameters
    i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            generate_write_to_parcel(t, c->statements, v,
                                stubClass->transact_reply,
                                Type::PARCELABLE_WRITE_RETURN_VALUE);
            hasOutParams = true;
        }

        arg = arg->next;
    }

    // return true
    c->statements->Add(new ReturnStatement(new LiteralExpression("NO_ERROR")));
    stubClass->transact_switch->cases.push_back(c);

    // == the proxy method ===================================================
    Method* proxy = new Method;
        proxy->comment = gather_comments(method->comments_token->extra);
        proxy->modifiers = PUBLIC | OVERRIDE;
        proxy->returnType = NAMES.Search(method->type.type.data);
        proxy->returnTypeDimension = method->type.dimension;
        proxy->name = method->name.data;
        proxy->statements = new StatementBlock;
        proxy->classType = proxyClass->type;
        arg = method->args;
        while (arg != NULL) {
            Type* vType = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(
                        vType, arg->name.data,
                        arg->type.dimension);
            UserDataType* userDataType = dynamic_cast<UserDataType*>(vType);
            InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(vType);
            if (userDataType != NULL) {
                v->modifiers |= POINTER;
            } else if (interfaceType != NULL) {
                v->modifiers |= STRONG_POINTER;
            }
            proxy->parameters.push_back(v/*new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension)*/);
            arg = arg->next;
        }
        //proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
    proxyClass->elements.push_back(proxy);

    // the parcels
    Variable* _data = new Variable(PARCEL_TYPE, "_data");
    //proxy->statements->Add(new VariableDeclaration(_data,
    //                            new MethodCall(PARCEL_TYPE, "obtain")));
    proxy->statements->Add(new VariableDeclaration(_data));

    Variable* _reply = NULL;
    if (!oneway) {
        _reply = new Variable(PARCEL_TYPE, "_reply");
        //proxy->statements->Add(new VariableDeclaration(_reply,
        //                            new MethodCall(PARCEL_TYPE, "obtain")));
        proxy->statements->Add(new VariableDeclaration(_reply));
    }

    // the return value
    _result = NULL;
    if (0 != strcmp(method->type.type.data, "void")) {
        _result = new Variable(proxy->returnType, "_result",
                method->type.dimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(proxy->returnType);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(proxy->returnType);
        if (userDataType != NULL) {
            _result->modifiers = POINTER;
        } else if (interfaceType != NULL) {
            _result->modifiers = STRONG_POINTER;
        }
        proxy->statements->Add(new VariableDeclaration(_result));
    }

    // try and finally
    //TryStatement* tryStatement = new TryStatement();
    //proxy->statements->Add(tryStatement);
    //FinallyStatement* finallyStatement = new FinallyStatement();
    //proxy->statements->Add(finallyStatement);

    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string

    /*tryStatement*/proxy->statements->Add(new MethodCall(_data, "writeInterfaceToken",
            1, new LiteralExpression(getDescriptor/*"DESCRIPTOR"*/)));

    // the parameters
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
        int dir = convert_direction(arg->direction.data);
        v->modifiers |= POINTER;
        if (dir == OUT_PARAMETER && arg->type.dimension != 0)
		{
            IfStatement* checklen = new IfStatement();
            checklen->expression = new Comparison(v, "==", NULL_VALUE);
            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
                        new LiteralExpression("-1")));
            checklen->elseif = new IfStatement();
            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
                        1, new FieldVariable(v, "length")));
            /*tryStatement*/proxy->statements->Add(checklen);
        }
        else if (dir & IN_PARAMETER)
        {
            // +JDN
            // ALERT LEAK !!!!
            Variable* localParcel = new Variable();
            localParcel->type = _data->type;
            localParcel->name = _data->name;
            localParcel->dimension = _data->dimension;
            localParcel->modifiers = _data->modifiers;
            localParcel->modifiers |= CALL_REFERENCE;
            // printf("generating parcel for %s (%s)\n", v->name.c_str(), v->type->Name().c_str());
            //generate_write_to_parcel(t, /*tryStatement*/proxy->statements, v, _data, 0);
            generate_write_to_parcel(t, /*tryStatement*/proxy->statements, v, localParcel, 0);
            // -JDN
        }
        else
        {
            // printf("else\n", "");
            // Do nothing
        }
        arg = arg->next;
    }

    // the transact call
    Variable* callReply = NULL;
    if (_reply != NULL) {
        callReply = new Variable(_reply->type, _reply->name);
        callReply->modifiers = CALL_REFERENCE;
    }
    MethodCall* call = new MethodCall(/*proxyClass->mRemote*/ new LiteralExpression("(*(remote()))"), "transact", 4,
                            new LiteralExpression(/*"Stub." +*/ transactCodeName),
                            _data, callReply ? callReply : NULL_VALUE,
                            new LiteralExpression(
                                          oneway ? /*"android.os.IBinder.FLAG_ONEWAY"*/ "IBinder::FLAG_ONEWAY" : "0"));
    /*tryStatement*/proxy->statements->Add(call);

    // throw back exceptions.
    if (_reply) {
        MethodCall* ex = new MethodCall(_reply, "readExceptionCode", 0);
        /*tryStatement*/proxy->statements->Add(ex);
    }

    // returning and cleanup
    if (_reply != NULL) {
        if (_result != NULL) {
            generate_create_from_parcel(proxy->returnType,
                    /*tryStatement*/proxy->statements, _result, _reply, &cl);
        }

        // the out/inout parameters
        arg = method->args;
        while (arg != NULL) {
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            UserDataType* userDataType = dynamic_cast<UserDataType*>(t);
            if (userDataType != NULL) v->modifiers = POINTER;
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                generate_read_from_parcel(t, /*tryStatement*/proxy->statements,
                                            v, _reply, &cl);
            }
            arg = arg->next;
        }

        //finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    }
    //finallyStatement->statements->Add(new MethodCall(_data, "recycle"));

    if (_result != NULL) {
        proxy->statements->Add(new ReturnStatement(_result));
    }
}
static void
generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
{
    arg_type* arg;
    Method* proxyMethod = new Method;
        proxyMethod->comment = gather_comments(method->comments_token->extra);
        proxyMethod->modifiers = PUBLIC;
        proxyMethod->returnType = VOID_TYPE;
        proxyMethod->returnTypeDimension = 0;
        proxyMethod->name = method->name.data;
        proxyMethod->statements = new StatementBlock;
    proxyClass->elements.push_back(proxyMethod);

    // The local variables
    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));

    // Add the arguments
    arg = method->args;
    while (arg != NULL) {
        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            // Function signature
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            proxyMethod->parameters.push_back(v);

            // Input parameter marshalling
            generate_write_to_data(t, proxyMethod->statements,
                    new StringLiteralExpression(arg->name.data), v, _data);
        }
        arg = arg->next;
    }

    // If there is a results interface for this class
    Expression* resultParameter;
    if (resultsInterfaceType != NULL) {
        // Result interface parameter
        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
        proxyMethod->parameters.push_back(resultListener);

        // Add the results dispatcher callback
        resultsDispatcherClass->needed = true;
        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
                new LiteralExpression(format_int(index)), resultListener);
    } else {
        resultParameter = NULL_VALUE;
    }

    // All proxy methods take an error parameter
    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
    proxyMethod->parameters.push_back(errorListener);

    // Call the broker
    proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
                "sendRpc", 5,
                proxyClass->endpoint,
                new StringLiteralExpression(method->name.data),
                new MethodCall(_data, "serialize"),
                resultParameter,
                errorListener));
}
void
DispatcherClass::AddMethod(const method_type* method)
{
    arg_type* arg;

    // The if/switch statement
    IfStatement* ifs = new IfStatement();
        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
                1, this->actionParam);
    StatementBlock* block = ifs->statements = new StatementBlock;
    if (this->dispatchIfStatement == NULL) {
        this->dispatchIfStatement = ifs;
        this->processMethod->statements->Add(dispatchIfStatement);
    } else {
        this->dispatchIfStatement->elseif = ifs;
        this->dispatchIfStatement = ifs;
    }
    
    // The call to decl (from above)
    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);

    // args
    Variable* classLoader = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        v->dimension = arg->type.dimension;

        // Unmarshall the parameter
        block->Add(new VariableDeclaration(v));
        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_data(t, block, arg->name.data, v,
                    this->requestData, &classLoader);
        } else {
            if (arg->type.dimension == 0) {
                block->Add(new Assignment(v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, block, v, this->requestData);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        // Add that parameter to the method call
        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // Add a final parameter: RpcContext. Contains data about
    // incoming request (e.g., certificate)
    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));

    Type* returnType = NAMES.Search(method->type.type.data);
    if (returnType == EVENT_FAKE_TYPE) {
        returnType = VOID_TYPE;
    }
    
    // the real call
    bool first = true;
    Variable* _result = NULL;
    if (returnType == VOID_TYPE) {
        block->Add(realCall);
    } else {
        _result = new Variable(returnType, "_result",
                                method->type.dimension);
        block->Add(new VariableDeclaration(_result, realCall));

        // need the result RpcData
        if (first) {
            block->Add(new Assignment(this->resultData,
                        new NewExpression(RPC_DATA_TYPE)));
            first = false;
        }

        // marshall the return value
        generate_write_to_data(returnType, block,
                new StringLiteralExpression("_result"), _result, this->resultData);
    }

    // out parameters
    int i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            // need the result RpcData
            if (first) {
                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
                first = false;
            }

            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
                    v, this->resultData);
        }

        arg = arg->next;
    }
}
static void
generate_method(const method_type* method, Class* interface,
                    StubClass* stubClass, ProxyClass* proxyClass, int index)
{
    arg_type* arg;
    int i;
    bool hasOutParams = false;

    const bool oneway = proxyClass->mOneWay || method->oneway;

    // == the TRANSACT_ constant =============================================
    string transactCodeName = "TRANSACTION_";
    transactCodeName += method->name.data;

    char transactCodeValue[50];
    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);

    Field* transactCode = new Field(STATIC | FINAL,
                            new Variable(INT_TYPE, transactCodeName));
    transactCode->value = transactCodeValue;
    stubClass->elements.push_back(transactCode);

    // == the declaration in the interface ===================================
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = PUBLIC;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;

    arg = method->args;
    while (arg != NULL) {
        decl->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
        arg = arg->next;
    }

    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);

    interface->elements.push_back(decl);

    // == the stub method ====================================================

    Case* c = new Case(transactCodeName);

    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);

    // interface token validation is the very first thing we do
    c->statements->Add(new MethodCall(stubClass->transact_data,
            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));

    // args
    Variable* cl = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        v->dimension = arg->type.dimension;

        c->statements->Add(new VariableDeclaration(v));

        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_parcel(t, c->statements, v,
                    stubClass->transact_data, &cl);
        } else {
            if (arg->type.dimension == 0) {
                c->statements->Add(new Assignment(
                                                v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, c->statements, v,
                        stubClass->transact_data);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // the real call
    Variable* _result = NULL;
    if (0 == strcmp(method->type.type.data, "void")) {
        c->statements->Add(realCall);

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }
    } else {
        _result = new Variable(decl->returnType, "_result",
                                decl->returnTypeDimension);
        c->statements->Add(new VariableDeclaration(_result, realCall));

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }

        // marshall the return value
        generate_write_to_parcel(decl->returnType, c->statements, _result,
                                    stubClass->transact_reply,
                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
    }

    // out parameters
    i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            generate_write_to_parcel(t, c->statements, v,
                                stubClass->transact_reply,
                                Type::PARCELABLE_WRITE_RETURN_VALUE);
            hasOutParams = true;
        }

        arg = arg->next;
    }

    // return true
    c->statements->Add(new ReturnStatement(TRUE_VALUE));
    stubClass->transact_switch->cases.push_back(c);

    // == the proxy method ===================================================
    Method* proxy = new Method;
        proxy->comment = gather_comments(method->comments_token->extra);
        proxy->modifiers = PUBLIC;
        proxy->returnType = NAMES.Search(method->type.type.data);
        proxy->returnTypeDimension = method->type.dimension;
        proxy->name = method->name.data;
        proxy->statements = new StatementBlock;
        arg = method->args;
        while (arg != NULL) {
            proxy->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
            arg = arg->next;
        }
        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
    proxyClass->elements.push_back(proxy);

    // the parcels
    Variable* _data = new Variable(PARCEL_TYPE, "_data");
    proxy->statements->Add(new VariableDeclaration(_data,
                                new MethodCall(PARCEL_TYPE, "obtain")));
    Variable* _reply = NULL;
    if (!oneway) {
        _reply = new Variable(PARCEL_TYPE, "_reply");
        proxy->statements->Add(new VariableDeclaration(_reply,
                                    new MethodCall(PARCEL_TYPE, "obtain")));
    }

    // the return value
    _result = NULL;
    if (0 != strcmp(method->type.type.data, "void")) {
        _result = new Variable(proxy->returnType, "_result",
                method->type.dimension);
        proxy->statements->Add(new VariableDeclaration(_result));
    }

    // try and finally
    TryStatement* tryStatement = new TryStatement();
    proxy->statements->Add(tryStatement);
    FinallyStatement* finallyStatement = new FinallyStatement();
    proxy->statements->Add(finallyStatement);

    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
            1, new LiteralExpression("DESCRIPTOR")));

    // the parameters
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
        int dir = convert_direction(arg->direction.data);
        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
            IfStatement* checklen = new IfStatement();
            checklen->expression = new Comparison(v, "==", NULL_VALUE);
            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
                        new LiteralExpression("-1")));
            checklen->elseif = new IfStatement();
            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
                        1, new FieldVariable(v, "length")));
            tryStatement->statements->Add(checklen);
        }
        else if (dir & IN_PARAMETER) {
            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
        }
        arg = arg->next;
    }

    // the transact call
    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
                            new LiteralExpression("Stub." + transactCodeName),
                            _data, _reply ? _reply : NULL_VALUE,
                            new LiteralExpression(
                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
    tryStatement->statements->Add(call);

    // throw back exceptions.
    if (_reply) {
        MethodCall* ex = new MethodCall(_reply, "readException", 0);
        tryStatement->statements->Add(ex);
    }

    // returning and cleanup
    if (_reply != NULL) {
        if (_result != NULL) {
            generate_create_from_parcel(proxy->returnType,
                    tryStatement->statements, _result, _reply, &cl);
        }

        // the out/inout parameters
        arg = method->args;
        while (arg != NULL) {
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                generate_read_from_parcel(t, tryStatement->statements,
                                            v, _reply, &cl);
            }
            arg = arg->next;
        }

        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    }
    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));

    if (_result != NULL) {
        proxy->statements->Add(new ReturnStatement(_result));
    }
}
void send()
{ 
    wildfire_packet_t * wp;
    net_packet_t * np;
    uint16_t sample;
    uint8_t sends;
    
    sends = 0;

    init_devs();
    mos_thread_set_suspend_state(SUSPEND_STATE_SLEEP);  //sets power save mode

    //just wait while in init state
    while (state != GO)
    {
	mos_mdelay(500);
    }

    while (1)
    {
	if (state == SLEEPNODE)
	{

	    disable_wind_speed();   //must disable the ext interrupts for power save sleep
	    //mos_thread_set_suspend_state(SUSPEND_STATE_SLEEP);  //sets power save mode
	    mos_thread_sleep(SLEEP_INTERVAL - 1000); //extra 1000 to make sure it wakes up early
	    //mos_thread_set_suspend_state(SUSPEND_STATE_IDLE); //idle mode
	    
	    while (state != GO)  //awake, but not ready yet.. so just wait
		mos_mdelay(250);
	    sends = 0;

	}

	//first populate the buffer with the net packet since this will
	//always be the header
	np = (net_packet_t *)&(sendBuf.data[0]);
	np->type = DATA;
	np->src = myID;
	np->dest = baseID;
	np->next_hop = myParentID;
	np->last_hop = myID;
	np->seqno = mySeqNo;
	np->pkt_dtb = myDTB;
	np->sender_dtb = myDTB;
	sendBuf.size = sizeof(net_packet_t);
	
	//for data packets, we now populate the buffer with the 
	//wildfire packet information.  Adding it to the end.
	wp = (wildfire_packet_t *)&(sendBuf.data[sendBuf.size]);
	//temp
	dev_open(DEV_MICA2_TEMP);
	dev_read(DEV_MICA2_TEMP, &sample, sizeof(sample));
	dev_close(DEV_MICA2_TEMP);
	wp->temp = convert_temp(sample);

	//battery
	dev_open(DEV_MICA2_BATTERY);
	dev_read(DEV_MICA2_BATTERY, &sample, sizeof(sample));
	dev_close(DEV_MICA2_BATTERY);
	wp->battery = sample;

	//humidity
	humidity_on();
	mos_mdelay(200); //settling time
	dev_open(DEV_ADC);
	dev_ioctl(DEV_ADC, ADC_SET_CHANNEL, AVR_ADC_CH_2);
	dev_read(DEV_ADC, &sample, sizeof(sample));
	dev_close(DEV_ADC);
	humidity_off();
	wp->humidity = convert_humidity(sample, wp->battery);

	//wind direction
	wind_dir_on();
	dev_open(DEV_ADC);
	dev_ioctl(DEV_ADC, ADC_SET_CHANNEL, AVR_ADC_CH_1);
	dev_read(DEV_ADC, &sample, sizeof(sample));
	dev_close(DEV_ADC);
	wind_dir_off();
	wp->wind_direction = convert_direction(sample);

	//wind speed
	wp->wind_speed = wind_speed;

	sendBuf.size += sizeof(wildfire_packet_t);

	//debug info:
        /*	printf("type\tsrc\tdest\tnext\tlast\tseq\tpktdtb\ts_dtb\n");
  printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", np->type, np->src, np->dest, np->next_hop, np->last_hop, np->seqno, np->pkt_dtb, np->sender_dtb);

  printf("temp\thmdty\tw_dir\tw_spd\tbat\n");
  printf("%d\t%d\t%d\t%d\t%d\n", wp->temp, wp->humidity, wp->wind_direction, wp->wind_speed, wp->battery);
        */    
    
	if (rate == 0 || sends < rate*myDTB)
	{
	    com_send(IFACE_RADIO, &sendBuf);
	    mySeqNo++;
	    sends++;
	}
	if (mySeqNo > 254)
	    mySeqNo = 0;
	mos_mdelay(1000);
    }
}