LCOV - code coverage report
Current view: directory - src/shared/srpc - invoke.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 124 87 70.2 %
Date: 2012-02-16 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             194 : static int TypeCheckArgs(const char* arg_types, NaClSrpcArg** alist) {
      30                 :   const char* p;
      31                 : 
      32             802 :   for (p = arg_types; '\0' != *p && ':' != *p; ++p, ++alist) {
      33             207 :     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             207 :     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             207 :         if ((*alist)->tag != (enum NaClSrpcArgType) *p) {
      50               0 :           return 0;
      51                 :         }
      52                 :         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                 :   }
      61             194 :   if (NULL != *alist) {
      62                 :     /* Too many arguments */
      63               0 :     return 0;
      64                 :   }
      65             194 :   return 1;
      66                 : }
      67                 : 
      68                 : /*
      69                 :  * Methods for invoking RPCs.
      70                 :  */
      71                 : NaClSrpcError NaClSrpcInvokeV(NaClSrpcChannel* channel,
      72                 :                               uint32_t rpc_number,
      73                 :                               NaClSrpcArg* args[],
      74              97 :                               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              97 :   if (NULL == channel) {
      83               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
      84                 :                 "NaClSrpcInvokeV: channel == NULL\n");
      85               0 :     return NACL_SRPC_RESULT_INTERNAL;
      86                 :   }
      87              97 :   if (NaClSrpcServiceMethodNameAndTypes(channel->client,
      88                 :                                         rpc_number,
      89                 :                                         &rpc_name,
      90                 :                                         &arg_types,
      91                 :                                         &ret_types)) {
      92                 :     /* Check input parameters for type conformance */
      93              97 :     if (!TypeCheckArgs(arg_types, args)) {
      94               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
      95                 :                   "NaClSrpcInvokeV(channel=%p): input arg mismatch\n",
      96                 :                   (void*) channel);
      97               0 :       return NACL_SRPC_RESULT_IN_ARG_TYPE_MISMATCH;
      98                 :     }
      99                 :     /* Check return values for type conformance */
     100              97 :     if (!TypeCheckArgs(ret_types, rets)) {
     101               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     102                 :                   "NaClSrpcInvokeV(channel=%p): output arg mismatch\n",
     103                 :                   (void*) channel);
     104               0 :       return NACL_SRPC_RESULT_OUT_ARG_TYPE_MISMATCH;
     105                 :     }
     106                 :   } else {
     107               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     108                 :                 "NaClSrpcInvokeV(channel=%p): bad rpc number\n",
     109                 :                 (void*) channel);
     110               0 :     return NACL_SRPC_RESULT_BAD_RPC_NUMBER;
     111                 :   }
     112              97 :   NaClSrpcLog(1,
     113                 :               "NaClSrpcInvokeV: request(channel=%p, rpc_number=%"NACL_PRIu32
     114                 :               ", rpc_name=\"%s\")\n",
     115                 :               (void*) channel,
     116                 :               rpc_number,
     117                 :               rpc_name);
     118                 : 
     119             202 :   for (i = 0; args[i] != NULL; i++ ) {
     120                 :     char buffer[256];
     121             105 :     NaClSrpcFormatArg(2, args[i], buffer, NACL_ARRAY_SIZE(buffer));
     122             105 :     NaClSrpcLog(2,
     123                 :                 "NaClSrpcInvokeV: request(channel=%p, args[%d]=%s)\n",
     124                 :                 (void*) channel,
     125                 :                 i,
     126                 :                 buffer);
     127                 :   }
     128                 : 
     129                 :   /*
     130                 :    * First we send the request.
     131                 :    * This requires sending args and the types and array sizes from rets.
     132                 :    */
     133              97 :   rpc.protocol_version = kNaClSrpcProtocolVersion;
     134              97 :   rpc.rpc_number = rpc_number;
     135              97 :   rpc.request_id = 0;
     136              97 :   rpc.result = NACL_SRPC_RESULT_OK;
     137              97 :   rpc.rets = rets;
     138              97 :   rpc.ret_types = ret_types;
     139              97 :   retval = NaClSrpcRequestWrite(channel, &rpc, args, rets);
     140              97 :   if (!retval) {
     141               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     142                 :                 "NaClSrpcInvokeV(channel=%p): rpc request send failed\n",
     143                 :                 (void*) channel);
     144               0 :     return NACL_SRPC_RESULT_INTERNAL;
     145                 :   }
     146                 : 
     147                 :   /* Then we wait for the response. */
     148              97 :   NaClSrpcRpcWait(channel, &rpc);
     149              97 :   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                 :               NaClSrpcErrorString(rpc.result));
     157                 : 
     158             199 :   for (i = 0; rets[i] != NULL; i++ ) {
     159                 :     char buffer[256];
     160             102 :     NaClSrpcFormatArg(2, rets[i], buffer, NACL_ARRAY_SIZE(buffer));
     161             102 :     NaClSrpcLog(2,
     162                 :                 "NaClSrpcInvokeV: response(channel=%p, rets[%d]=%s)\n",
     163                 :                 (void*) channel,
     164                 :                 i,
     165                 :                 buffer);
     166                 :   }
     167                 : 
     168              97 :   return rpc.result;
     169                 : }
     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              52 : static void FreeArgs(NaClSrpcArg** vec) {
     274              52 :   if (NULL == vec) {
     275               0 :     return;
     276                 :   }
     277              52 :   free(vec[0]);
     278              52 :   free(vec);
     279                 : }
     280                 : 
     281              52 : static NaClSrpcArg** AllocArgs(size_t vector_length) {
     282                 :   NaClSrpcArg** vec;
     283                 :   size_t vector_length_in_bytes;
     284                 :   size_t i;
     285                 : 
     286                 :   /* Allocate the index vector. */
     287              52 :   if (NACL_SRPC_MAX_ARGS < vector_length) {
     288               0 :     return NULL;
     289                 :   }
     290              52 :   vector_length_in_bytes = (vector_length + 1) * sizeof *vec;
     291              52 :   vec = (NaClSrpcArg **) malloc(vector_length_in_bytes);
     292              52 :   memset(vec, 0, vector_length_in_bytes);
     293              52 :   if (NULL == vec) {
     294               0 :     FreeArgs(vec);
     295               0 :     return NULL;
     296                 :   }
     297                 :   /* Allocate and initialize the arguments (if any). */
     298              52 :   if (0 != vector_length) {
     299              26 :     vec[0] = (NaClSrpcArg *) malloc(vector_length * sizeof *vec[0]);
     300              26 :     if (NULL == vec[0]) {
     301               0 :       FreeArgs(vec);
     302               0 :       return NULL;
     303                 :     }
     304              63 :     for (i = 0; i < vector_length; ++i) {
     305              37 :       NaClSrpcArgCtor(vec[0] + i);
     306                 :     }
     307                 :   }
     308                 :   /* Set the index vector to point to the arguments. */
     309              63 :   for (i = 1; i < vector_length; ++i) {
     310              11 :     vec[i] = vec[0] + i;
     311                 :   }
     312              52 :   vec[vector_length] = 0;
     313              52 :   return vec;
     314                 : }
     315                 : 
     316                 : NaClSrpcError NaClSrpcInvokeVaList(NaClSrpcChannel  *channel,
     317                 :                                    uint32_t         rpc_num,
     318                 :                                    va_list          in_va,
     319              26 :                                    va_list          out_va) {
     320                 :   char const        *rpc_name;
     321                 :   char const        *arg_types;
     322                 :   char const        *ret_types;
     323                 :   size_t            num_in;
     324                 :   size_t            num_out;
     325                 :   uint32_t          i;
     326              26 :   NaClSrpcArg       **inv = NULL;
     327              26 :   NaClSrpcArg       **outv = NULL;
     328                 :   char const        *p;
     329                 :   NaClSrpcError     rv;
     330                 : 
     331              26 :   if (NULL == channel) {
     332               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     333                 :                 "NaClSrpcInvokeVaList: channel == NULL\n");
     334               0 :     return NACL_SRPC_RESULT_INTERNAL;
     335                 :   }
     336                 : 
     337              26 :   if (!NaClSrpcServiceMethodNameAndTypes(channel->client,
     338                 :                                          rpc_num,
     339                 :                                          &rpc_name,
     340                 :                                          &arg_types,
     341                 :                                          &ret_types)) {
     342                 :     /*
     343                 :      * If rpc_number is out of range, this will return an error before
     344                 :      * communicating with the server.
     345                 :      */
     346               0 :     return NACL_SRPC_RESULT_BAD_RPC_NUMBER;
     347                 :   }
     348                 : 
     349              26 :   num_in = strlen(arg_types);
     350              26 :   num_out = strlen(ret_types);
     351                 : 
     352              26 :   if (NACL_SRPC_MAX_ARGS < num_in || NACL_SRPC_MAX_ARGS < num_out) {
     353               0 :     return NACL_SRPC_RESULT_APP_ERROR;
     354                 :   }
     355                 : 
     356              26 :   rv = NACL_SRPC_RESULT_NO_MEMORY;
     357              26 :   inv = AllocArgs(num_in);
     358              26 :   if (NULL == inv) {
     359               0 :     goto done;
     360                 :   }
     361              26 :   outv = AllocArgs(num_out);
     362              26 :   if (NULL == outv) {
     363               0 :     goto done;
     364                 :   }
     365                 : 
     366              49 :   for (i = 0, p = arg_types; i < num_in; ++i, ++p) {
     367              23 :     ARGRET_SWITCH(ARG, in_va, inv[i]);
     368              23 :     inv[i]->tag = (enum NaClSrpcArgType) *p;
     369                 :   }
     370              40 :   for (i = 0, p = ret_types; i < num_out; ++i, ++p) {
     371              14 :     ARGRET_SWITCH(RETINIT, in_va, outv[i]);
     372              14 :     outv[i]->tag = (enum NaClSrpcArgType) *p;
     373                 :   }
     374                 : 
     375              26 :   rv = NaClSrpcInvokeV(channel, rpc_num, inv, outv);
     376                 : 
     377              49 :   for (i = 0, p = arg_types; i < num_in; ++i, ++p) {
     378              23 :     ARGRET_SWITCH(SKIP, out_va, inv[i]);
     379                 :   }
     380              40 :   for (i = 0, p = ret_types; i < num_out; ++i, ++p) {
     381              14 :     ARGRET_SWITCH(RET, out_va, outv[i]);
     382                 :   }
     383                 : 
     384              26 :  done:
     385              26 :   FreeArgs(outv);
     386              26 :   FreeArgs(inv);
     387              26 :   return rv;
     388                 : }
     389                 : 
     390                 : NaClSrpcError NaClSrpcInvoke(NaClSrpcChannel  *channel,
     391                 :                              uint32_t         rpc_num,
     392               0 :                              ...) {
     393                 :   va_list       in_va;
     394                 :   va_list       out_va;
     395                 :   NaClSrpcError rv;
     396                 : 
     397               0 :   va_start(in_va, rpc_num);
     398               0 :   va_start(out_va, rpc_num);
     399                 : 
     400               0 :   rv = NaClSrpcInvokeVaList(channel, rpc_num, in_va, out_va);
     401                 :   /*
     402                 :    * Before the messages are sent to the server, rpc_num will be checked
     403                 :    * for validity.
     404                 :    */
     405                 : 
     406               0 :   va_end(out_va);
     407               0 :   va_end(in_va);
     408                 : 
     409               0 :   return rv;
     410                 : }
     411                 : 
     412                 : NaClSrpcError NaClSrpcInvokeBySignature(NaClSrpcChannel  *channel,
     413                 :                                         const char       *rpc_signature,
     414              26 :                                         ...) {
     415                 :   uint32_t            rpc_num;
     416                 :   va_list             in_va;
     417                 :   va_list             out_va;
     418                 :   NaClSrpcError       rv;
     419                 : 
     420              26 :   if (NULL == channel) {
     421               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     422                 :                 "NaClSrpcInvokeBySignature: channel == NULL\n");
     423               0 :     return NACL_SRPC_RESULT_INTERNAL;
     424                 :   }
     425              26 :   rpc_num = NaClSrpcServiceMethodIndex(channel->client, rpc_signature);
     426              26 :   if (kNaClSrpcInvalidMethodIndex == rpc_num) {
     427                 :     /*
     428                 :      * kNaClSrpcInvalidMethodIndex is returned when rpc_name does not match
     429                 :      * any method in the client service.  Explicitly check and return an error.
     430                 :      */
     431               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     432                 :                 "NaClSrpcInvokeBySignature(channel=%p):"
     433                 :                 "missing signature [%s]\n",
     434                 :                 (void*) channel,
     435                 :                 rpc_signature);
     436               0 :     return NACL_SRPC_RESULT_APP_ERROR;
     437                 :   }
     438                 : 
     439              26 :   va_start(in_va, rpc_signature);
     440              26 :   va_start(out_va, rpc_signature);
     441                 : 
     442              26 :   rv = NaClSrpcInvokeVaList(channel, rpc_num, in_va, out_va);
     443                 : 
     444              26 :   va_end(out_va);
     445              26 :   va_end(in_va);
     446                 : 
     447              26 :   return rv;
     448                 : }

Generated by: LCOV version 1.7