LCOV - code coverage report
Current view: directory - src/shared/srpc - invoke.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 138 99 71.7 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl SRPC library.  A primitive rpc library.
       9                 :  */
      10                 : 
      11                 : #include <stdarg.h>
      12                 : #include <stdlib.h>
      13                 : #include <string.h>
      14                 : 
      15                 : #include "native_client/src/include/portability.h"
      16                 : #include "native_client/src/include/nacl_macros.h"
      17                 : #ifdef __native_client__
      18                 : #include <inttypes.h>
      19                 : #else
      20                 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
      21                 : #endif  /* __native_client__ */
      22                 : #include "native_client/src/shared/srpc/nacl_srpc.h"
      23                 : #include "native_client/src/shared/srpc/nacl_srpc_internal.h"
      24                 : 
      25                 : 
      26                 : /*
      27                 :  * Utility method for type checking argument lists.
      28                 :  */
      29               2 : static int TypeCheckArgs(const char* arg_types, NaClSrpcArg** alist) {
      30                 :   const char* p;
      31                 : 
      32               2 :   for (p = arg_types; '\0' != *p && ':' != *p; ++p, ++alist) {
      33               2 :     if (NULL == *alist) {
      34                 :       /* Too few arguments */
      35               0 :       return 0;
      36                 :     }
      37                 :     /* This code could be more compact by using a 256 entry table. */
      38               2 :     switch (*p) {
      39                 :       case NACL_SRPC_ARG_TYPE_BOOL:
      40                 :       case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
      41                 :       case NACL_SRPC_ARG_TYPE_DOUBLE:
      42                 :       case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
      43                 :       case NACL_SRPC_ARG_TYPE_HANDLE:
      44                 :       case NACL_SRPC_ARG_TYPE_INT:
      45                 :       case NACL_SRPC_ARG_TYPE_INT_ARRAY:
      46                 :       case NACL_SRPC_ARG_TYPE_LONG:
      47                 :       case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
      48                 :       case NACL_SRPC_ARG_TYPE_STRING:
      49               2 :         if ((*alist)->tag != (enum NaClSrpcArgType) *p) {
      50               0 :           return 0;
      51                 :         }
      52               2 :         break;
      53                 :       /* These cases are added to avoid warnings.  */
      54                 :       case NACL_SRPC_ARG_TYPE_OBJECT:
      55                 :       case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
      56                 :       case NACL_SRPC_ARG_TYPE_INVALID:
      57                 :       default:
      58               0 :         return 0;
      59                 :     }
      60               2 :   }
      61               2 :   if (NULL != *alist) {
      62                 :     /* Too many arguments */
      63               0 :     return 0;
      64                 :   }
      65               2 :   return 1;
      66               2 : }
      67                 : 
      68                 : /*
      69                 :  * Methods for invoking RPCs.
      70                 :  */
      71                 : NaClSrpcError NaClSrpcInvokeV(NaClSrpcChannel* channel,
      72                 :                               uint32_t rpc_number,
      73                 :                               NaClSrpcArg* args[],
      74               2 :                               NaClSrpcArg* rets[]) {
      75                 :   int i;
      76                 :   NaClSrpcRpc        rpc;
      77                 :   NaClSrpcError      retval;
      78                 :   const char*        rpc_name;
      79                 :   const char*        arg_types;
      80                 :   const char*        ret_types;
      81                 : 
      82               2 :   if (NULL == channel) {
      83                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
      84               0 :                 "NaClSrpcInvokeV: channel == NULL\n");
      85               0 :     return NACL_SRPC_RESULT_INTERNAL;
      86                 :   }
      87                 :   if (NaClSrpcServiceMethodNameAndTypes(channel->client,
      88                 :                                         rpc_number,
      89                 :                                         &rpc_name,
      90                 :                                         &arg_types,
      91               2 :                                         &ret_types)) {
      92                 :     /* Check input parameters for type conformance */
      93               2 :     if (!TypeCheckArgs(arg_types, args)) {
      94                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
      95                 :                   "NaClSrpcInvokeV(channel=%p): input arg mismatch\n",
      96               0 :                   (void*) channel);
      97               0 :       return NACL_SRPC_RESULT_IN_ARG_TYPE_MISMATCH;
      98                 :     }
      99                 :     /* Check return values for type conformance */
     100               2 :     if (!TypeCheckArgs(ret_types, rets)) {
     101                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     102                 :                   "NaClSrpcInvokeV(channel=%p): output arg mismatch\n",
     103               0 :                   (void*) channel);
     104               0 :       return NACL_SRPC_RESULT_OUT_ARG_TYPE_MISMATCH;
     105                 :     }
     106               2 :   } else {
     107                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     108                 :                 "NaClSrpcInvokeV(channel=%p): bad rpc number\n",
     109               0 :                 (void*) channel);
     110               0 :     return NACL_SRPC_RESULT_BAD_RPC_NUMBER;
     111                 :   }
     112                 :   NaClSrpcLog(1,
     113                 :               "NaClSrpcInvokeV: request(channel=%p, rpc_number=%"NACL_PRIu32
     114                 :               ", rpc_name=\"%s\")\n",
     115                 :               (void*) channel,
     116                 :               rpc_number,
     117               2 :               rpc_name);
     118                 : 
     119               2 :   for (i = 0; args[i] != NULL; i++ ) {
     120                 :     char buffer[256];
     121               1 :     NaClSrpcFormatArg(2, args[i], buffer, NACL_ARRAY_SIZE(buffer));
     122                 :     NaClSrpcLog(2,
     123                 :                 "NaClSrpcInvokeV: request(channel=%p, args[%d]=%s)\n",
     124                 :                 (void*) channel,
     125                 :                 i,
     126               1 :                 buffer);
     127               1 :   }
     128                 : 
     129                 :   /*
     130                 :    * First we send the request.
     131                 :    * This requires sending args and the types and array sizes from rets.
     132                 :    */
     133               2 :   rpc.protocol_version = kNaClSrpcProtocolVersion;
     134               2 :   rpc.rpc_number = rpc_number;
     135               2 :   rpc.request_id = 0;
     136               2 :   rpc.result = NACL_SRPC_RESULT_OK;
     137               2 :   rpc.rets = rets;
     138               2 :   rpc.ret_types = ret_types;
     139               2 :   retval = NaClSrpcRequestWrite(channel, &rpc, args, rets);
     140               2 :   if (!retval) {
     141                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     142                 :                 "NaClSrpcInvokeV(channel=%p): rpc request send failed\n",
     143               0 :                 (void*) channel);
     144               0 :     return NACL_SRPC_RESULT_INTERNAL;
     145                 :   }
     146                 : 
     147                 :   /* Then we wait for the response. */
     148               2 :   NaClSrpcRpcWait(channel, &rpc);
     149                 :   NaClSrpcLog(1,
     150                 :               "NaClSrpcInvokeV: response(channel=%p, rpc_number=%"NACL_PRIu32
     151                 :               ", rpc_name=\"%s\", result=%d, string=\"%s\")\n",
     152                 :               (void*) channel,
     153                 :               rpc_number,
     154                 :               rpc_name,
     155                 :               rpc.result,
     156               2 :               NaClSrpcErrorString(rpc.result));
     157                 : 
     158               2 :   for (i = 0; rets[i] != NULL; i++ ) {
     159                 :     char buffer[256];
     160               2 :     NaClSrpcFormatArg(2, rets[i], buffer, NACL_ARRAY_SIZE(buffer));
     161                 :     NaClSrpcLog(2,
     162                 :                 "NaClSrpcInvokeV: response(channel=%p, rets[%d]=%s)\n",
     163                 :                 (void*) channel,
     164                 :                 i,
     165               2 :                 buffer);
     166               2 :   }
     167                 : 
     168               2 :   return rpc.result;
     169               2 : }
     170                 : 
     171                 : /*
     172                 :  * Parameter passing and return involves a significant amount of replication
     173                 :  * that could be handled through templates.  What follows is a set of
     174                 :  * macros for that task.
     175                 :  */
     176                 : /*
     177                 :  * Some steps involve skipping a parameter in a va_arg list.
     178                 :  */
     179                 : #define SKIP(va, impl_type) \
     180                 :     (void) va_arg(va, impl_type);
     181                 : 
     182                 : /*
     183                 :  * The first phase is the args[] vector construction.
     184                 :  */
     185                 : #define SCALAR_ARG(arg, field, va, impl_type)     \
     186                 :     (arg)->field = va_arg(va, impl_type)
     187                 : #define ARRAY_ARG(arg, array_name, va, impl_type) \
     188                 :     (arg)->u.count = va_arg(va, uint32_t);        \
     189                 :     (arg)->array_name = va_arg(va, impl_type)
     190                 : #define BOOL_ARG(arg, field, va, impl_type)       \
     191                 :     (arg)->u.bval = (va_arg(va, impl_type) != 0)
     192                 : 
     193                 : /*
     194                 :  * The second phase is the rets[] vector construction before invocation.
     195                 :  */
     196                 : #define SCALAR_RETINIT(arg, field, va, impl_type)     \
     197                 :     (arg)->field = (impl_type) 0;                     \
     198                 :     SKIP(va, impl_type *)
     199                 : #define ARRAY_RETINIT(arg, array_name, va, impl_type) \
     200                 :     (arg)->u.count = *va_arg(va, uint32_t*);          \
     201                 :     (arg)->array_name = va_arg(va, impl_type)
     202                 : #define BOOL_RETINIT(arg, field, va, impl_type)       \
     203                 :     SKIP(va, impl_type *)
     204                 : 
     205                 : /*
     206                 :  * The third phase is skipping the args[] after invocation.
     207                 :  */
     208                 : #define SCALAR_SKIP(arg, field, va, impl_type)     \
     209                 :     SKIP(va, impl_type)
     210                 : #define ARRAY_SKIP(arg, array_name, va, impl_type) \
     211                 :     SKIP(va, uint32_t)                             \
     212                 :     SKIP(va, impl_type)
     213                 : #define BOOL_SKIP(arg, field, va, impl_type)       \
     214                 :     SCALAR_SKIP(arg, field, va, impl_type)
     215                 : 
     216                 : /*
     217                 :  * The fourth phase is copying the rets[] into the va_args after invocation.
     218                 :  */
     219                 : #define SCALAR_RET(arg, field, va, impl_type)     \
     220                 :     *va_arg(va, impl_type *) = (arg)->field
     221                 : #define ARRAY_RET(arg, array_name, va, impl_type) \
     222                 :     *va_arg(va, uint32_t*) = (arg)->u.count;      \
     223                 :     SKIP(va, impl_type)
     224                 : #define BOOL_RET(arg, field, va, impl_type)       \
     225                 :     *va_arg(va, impl_type *) = ((arg)->field != 0)
     226                 : 
     227                 : /*
     228                 :  * All the phases consist of a loop around a switch enumerating types.
     229                 :  */
     230                 : #define ARGRET_SWITCH(phase, va, arg)                           \
     231                 :     switch (*p) {                                               \
     232                 :       case NACL_SRPC_ARG_TYPE_BOOL:                             \
     233                 :         BOOL_##phase(arg, u.bval, va, int);                     \
     234                 :         break;                                                  \
     235                 :       case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:                       \
     236                 :         ARRAY_##phase(arg, arrays.carr, va, char*);             \
     237                 :         break;                                                  \
     238                 :       case NACL_SRPC_ARG_TYPE_DOUBLE:                           \
     239                 :         SCALAR_##phase(arg, u.dval, va, double);                \
     240                 :         break;                                                  \
     241                 :       case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:                     \
     242                 :         ARRAY_##phase(arg, arrays.darr, va, double*);           \
     243                 :         break;                                                  \
     244                 :       case NACL_SRPC_ARG_TYPE_HANDLE:                           \
     245                 :         SCALAR_##phase(arg, u.hval, va, NaClSrpcImcDescType);   \
     246                 :         break;                                                  \
     247                 :       case NACL_SRPC_ARG_TYPE_INT:                              \
     248                 :         SCALAR_##phase(arg, u.ival, va, int32_t);               \
     249                 :         break;                                                  \
     250                 :       case NACL_SRPC_ARG_TYPE_INT_ARRAY:                        \
     251                 :         ARRAY_##phase(arg, arrays.iarr, va, int32_t*);          \
     252                 :         break;                                                  \
     253                 :       case NACL_SRPC_ARG_TYPE_LONG:                             \
     254                 :         SCALAR_##phase(arg, u.lval, va, int64_t);               \
     255                 :         break;                                                  \
     256                 :       case NACL_SRPC_ARG_TYPE_LONG_ARRAY:                       \
     257                 :         ARRAY_##phase(arg, arrays.larr, va, int64_t*);          \
     258                 :         break;                                                  \
     259                 :       case NACL_SRPC_ARG_TYPE_STRING:                           \
     260                 :         SCALAR_##phase(arg, arrays.str, va, char*);             \
     261                 :         break;                                                  \
     262                 :       /*                                                        \
     263                 :        * The two cases below are added to avoid warnings,       \
     264                 :        * they are only used  in the plugin code                 \
     265                 :        */                                                       \
     266                 :       case NACL_SRPC_ARG_TYPE_OBJECT:                           \
     267                 :       case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:                    \
     268                 :       default:                                                  \
     269                 :         rv = NACL_SRPC_RESULT_APP_ERROR;                        \
     270                 :         goto done;                                              \
     271                 :     }
     272                 : 
     273               2 : static void FreeArgs(NaClSrpcArg** vec) {
     274               2 :   if (NULL == vec) {
     275               0 :     return;
     276                 :   }
     277               2 :   free(vec[0]);
     278               2 :   free(vec);
     279               2 : }
     280                 : 
     281               2 : static NaClSrpcArg** AllocArgs(size_t vector_length) {
     282                 :   NaClSrpcArg** vec;
     283                 :   size_t i;
     284                 : 
     285                 :   /* Allocate the index vector. */
     286               2 :   if (NACL_SRPC_MAX_ARGS < vector_length) {
     287               0 :     return NULL;
     288                 :   }
     289               2 :   vec = (NaClSrpcArg **) calloc(vector_length + 1, sizeof *vec);
     290               2 :   if (NULL == vec) {
     291               0 :     return NULL;
     292                 :   }
     293                 :   /* Allocate and initialize the arguments (if any). */
     294               2 :   if (0 != vector_length) {
     295               2 :     vec[0] = (NaClSrpcArg *) malloc(vector_length * sizeof *vec[0]);
     296               2 :     if (NULL == vec[0]) {
     297               0 :       FreeArgs(vec);
     298               0 :       return NULL;
     299                 :     }
     300               2 :     for (i = 0; i < vector_length; ++i) {
     301               2 :       NaClSrpcArgCtor(vec[0] + i);
     302               2 :     }
     303                 :   }
     304                 :   /* Set the index vector to point to the arguments. */
     305               2 :   for (i = 1; i < vector_length; ++i) {
     306               0 :     vec[i] = vec[0] + i;
     307               0 :   }
     308               2 :   vec[vector_length] = 0;
     309               2 :   return vec;
     310               2 : }
     311                 : 
     312                 : NaClSrpcError NaClSrpcInvokeVaList(NaClSrpcChannel  *channel,
     313                 :                                    uint32_t         rpc_num,
     314                 :                                    va_list          in_va,
     315               2 :                                    va_list          out_va) {
     316                 :   char const        *rpc_name;
     317                 :   char const        *arg_types;
     318                 :   char const        *ret_types;
     319                 :   size_t            num_in;
     320                 :   size_t            num_out;
     321                 :   uint32_t          i;
     322               2 :   NaClSrpcArg       **inv = NULL;
     323               2 :   NaClSrpcArg       **outv = NULL;
     324                 :   char const        *p;
     325                 :   NaClSrpcError     rv;
     326                 : 
     327               2 :   if (NULL == channel) {
     328                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     329               0 :                 "NaClSrpcInvokeVaList: channel == NULL\n");
     330               0 :     return NACL_SRPC_RESULT_INTERNAL;
     331                 :   }
     332                 : 
     333                 :   if (!NaClSrpcServiceMethodNameAndTypes(channel->client,
     334                 :                                          rpc_num,
     335                 :                                          &rpc_name,
     336                 :                                          &arg_types,
     337               2 :                                          &ret_types)) {
     338                 :     /*
     339                 :      * If rpc_number is out of range, this will return an error before
     340                 :      * communicating with the server.
     341                 :      */
     342               0 :     return NACL_SRPC_RESULT_BAD_RPC_NUMBER;
     343                 :   }
     344                 : 
     345               2 :   num_in = strlen(arg_types);
     346               2 :   num_out = strlen(ret_types);
     347                 : 
     348               2 :   if (NACL_SRPC_MAX_ARGS < num_in || NACL_SRPC_MAX_ARGS < num_out) {
     349               0 :     return NACL_SRPC_RESULT_APP_ERROR;
     350                 :   }
     351                 : 
     352               2 :   rv = NACL_SRPC_RESULT_NO_MEMORY;
     353               2 :   inv = AllocArgs(num_in);
     354               2 :   if (NULL == inv) {
     355               0 :     goto done;
     356                 :   }
     357               2 :   outv = AllocArgs(num_out);
     358               2 :   if (NULL == outv) {
     359               0 :     goto done;
     360                 :   }
     361                 : 
     362               2 :   for (i = 0, p = arg_types; i < num_in; ++i, ++p) {
     363               1 :     ARGRET_SWITCH(ARG, in_va, inv[i]);
     364               1 :     inv[i]->tag = (enum NaClSrpcArgType) *p;
     365               1 :   }
     366               2 :   for (i = 0, p = ret_types; i < num_out; ++i, ++p) {
     367               1 :     ARGRET_SWITCH(RETINIT, in_va, outv[i]);
     368               1 :     outv[i]->tag = (enum NaClSrpcArgType) *p;
     369               1 :   }
     370                 : 
     371               2 :   rv = NaClSrpcInvokeV(channel, rpc_num, inv, outv);
     372                 : 
     373               2 :   for (i = 0, p = arg_types; i < num_in; ++i, ++p) {
     374               1 :     ARGRET_SWITCH(SKIP, out_va, inv[i]);
     375               1 :   }
     376               2 :   for (i = 0, p = ret_types; i < num_out; ++i, ++p) {
     377               1 :     ARGRET_SWITCH(RET, out_va, outv[i]);
     378               1 :   }
     379                 : 
     380                 :  done:
     381               2 :   FreeArgs(outv);
     382               2 :   FreeArgs(inv);
     383               2 :   return rv;
     384               2 : }
     385                 : 
     386                 : NaClSrpcError NaClSrpcInvoke(NaClSrpcChannel  *channel,
     387                 :                              uint32_t         rpc_num,
     388               0 :                              ...) {
     389                 :   va_list       in_va;
     390                 :   va_list       out_va;
     391                 :   NaClSrpcError rv;
     392                 : 
     393               0 :   va_start(in_va, rpc_num);
     394               0 :   va_start(out_va, rpc_num);
     395                 : 
     396               0 :   rv = NaClSrpcInvokeVaList(channel, rpc_num, in_va, out_va);
     397                 :   /*
     398                 :    * Before the messages are sent to the server, rpc_num will be checked
     399                 :    * for validity.
     400                 :    */
     401                 : 
     402               0 :   va_end(out_va);
     403               0 :   va_end(in_va);
     404                 : 
     405               0 :   return rv;
     406               0 : }
     407                 : 
     408                 : NaClSrpcError NaClSrpcInvokeBySignature(NaClSrpcChannel  *channel,
     409                 :                                         const char       *rpc_signature,
     410               2 :                                         ...) {
     411                 :   uint32_t            rpc_num;
     412                 :   va_list             in_va;
     413                 :   va_list             out_va;
     414                 :   NaClSrpcError       rv;
     415                 : 
     416               2 :   if (NULL == channel) {
     417                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     418               0 :                 "NaClSrpcInvokeBySignature: channel == NULL\n");
     419               0 :     return NACL_SRPC_RESULT_INTERNAL;
     420                 :   }
     421               2 :   rpc_num = NaClSrpcServiceMethodIndex(channel->client, rpc_signature);
     422               2 :   if (kNaClSrpcInvalidMethodIndex == rpc_num) {
     423                 :     /*
     424                 :      * kNaClSrpcInvalidMethodIndex is returned when rpc_name does not match
     425                 :      * any method in the client service.  Explicitly check and return an error.
     426                 :      */
     427                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     428                 :                 "NaClSrpcInvokeBySignature(channel=%p):"
     429                 :                 "missing signature [%s]\n",
     430                 :                 (void*) channel,
     431               0 :                 rpc_signature);
     432               0 :     return NACL_SRPC_RESULT_APP_ERROR;
     433                 :   }
     434                 : 
     435               2 :   va_start(in_va, rpc_signature);
     436               2 :   va_start(out_va, rpc_signature);
     437                 : 
     438               2 :   rv = NaClSrpcInvokeVaList(channel, rpc_num, in_va, out_va);
     439                 : 
     440               2 :   va_end(out_va);
     441               2 :   va_end(in_va);
     442                 : 
     443               2 :   return rv;
     444               2 : }

Generated by: LCOV version 1.7