LCOV - code coverage report
Current view: directory - src/shared/srpc - rpc_serialize.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 425 315 74.1 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 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 simple RPC over IMC mechanism.
       9                 :  */
      10                 : 
      11                 : #include <errno.h>
      12                 : #include <stdio.h>
      13                 : #include <stdlib.h>
      14                 : #include <string.h>
      15                 : #include <sys/types.h>
      16                 : 
      17                 : #include "native_client/src/include/portability.h"
      18                 : #include "native_client/src/include/nacl_macros.h"
      19                 : #include "native_client/src/shared/srpc/nacl_srpc.h"
      20                 : #include "native_client/src/shared/srpc/nacl_srpc_internal.h"
      21                 : #include "native_client/src/shared/srpc/nacl_srpc_message.h"
      22                 : 
      23                 : #ifdef __native_client__
      24                 : #define NACL_ABI_EIO EIO
      25                 : #define NACL_ABI_EINVAL EINVAL
      26                 : #else
      27                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      28                 : #endif
      29                 : 
      30                 : #ifndef SIZE_T_MAX
      31                 : # define SIZE_T_MAX (~((size_t) 0))
      32                 : #endif
      33                 : 
      34                 : /*
      35                 :  * Message formats:
      36                 :  *
      37                 :  * SRPC communicates using two message types, requests and responses.
      38                 :  * Both are communicated with a header (NaClSrpcHeader below) prepended.
      39                 :  *
      40                 :  * Requests and responses also convey vectors of parameters that are
      41                 :  * represented in memory by NaClSrpcArg.  Because NaClSrpcArgs may have a
      42                 :  * non-fixed amount of additional memory associated (strings, arrays, etc.),
      43                 :  * the form communicated separates the vectors of NaClSrpcArgs into a vector
      44                 :  * of fixed length structs (ArgFixed) and a region of non-fixed memory.
      45                 :  *
      46                 :  * request:
      47                 :  *   RpcHeader       header
      48                 :  *   -- header info, value_len and template_len
      49                 :  *      where value_len <= NACL_SRPC_MAX_ARGS, and
      50                 :  *            template_len <= NACL_SRPC_MAX_ARGS
      51                 :  *   ArgFixed        templates[template_len]
      52                 :  *   -- conveys the types and sizes of rets
      53                 :  *   ArgFixed        values[value_len]
      54                 :  *   -- conveys the scalar values, and array types and sizes of args
      55                 :  *   char            nonfixed[]
      56                 :  *   -- the bytes used by strings, arrays, etc., in the elements of args in
      57                 :  *      the order seen in args
      58                 :  *
      59                 :  * response:
      60                 :  *   RpcHeader       header
      61                 :  *   -- header info, value_len and template_len
      62                 :  *      where value_len <= NACL_SRPC_MAX_ARGS, and template_len == 0
      63                 :  *   ArgFixed        values[value_len]
      64                 :  *   -- conveys the scalar values, and array types and sizes of rets
      65                 :  *   char            nonfixed[]
      66                 :  *   -- the bytes used by strings, arrays, etc., in the elements of rets in
      67                 :  *      the order seen in rets
      68                 :  */
      69                 : 
      70                 : #define HEADER_IOV_ENTRY_MAX     1
      71                 : #define TEMPLATE_IOV_ENTRY_MAX   NACL_SRPC_MAX_ARGS
      72                 : #define VALUE_IOV_ENTRY_MAX      NACL_SRPC_MAX_ARGS
      73                 : #define NONFIXED_IOV_ENTRY_MAX   NACL_SRPC_MAX_ARGS
      74                 : #define IOV_ENTRY_MAX            (HEADER_IOV_ENTRY_MAX + \
      75                 :                                   TEMPLATE_IOV_ENTRY_MAX + \
      76                 :                                   VALUE_IOV_ENTRY_MAX + \
      77                 :                                   NONFIXED_IOV_ENTRY_MAX)
      78                 : 
      79                 : /*
      80                 :  * RpcFixed is the fixed portion of NaClSrpcRpc serialized to the channel.
      81                 :  */
      82                 : struct RpcFixed {
      83                 :   NACL_SRPC_RPC_SERIALIZED_FIELDS;
      84                 : };
      85                 : static const size_t kRpcSize = sizeof(struct RpcFixed);
      86                 : 
      87                 : /*
      88                 :  * ArgFixed is the fixed portion of NaClSrpcArg serialized to the channel.
      89                 :  */
      90                 : struct ArgFixed {
      91                 :   NACL_SRPC_ARG_SERIALIZED_FIELDS;
      92                 : };
      93                 : static const size_t kArgSize = sizeof(struct ArgFixed);
      94                 : 
      95                 : typedef enum {
      96                 :   BoolFalse = 0,
      97                 :   BoolTrue = 1,
      98                 : } BoolValue;
      99                 : 
     100               8 : static ssize_t ErrnoFromImcRet(ssize_t imc_ret) {
     101               8 :   if (0 > imc_ret) {
     102               8 :     return imc_ret;
     103                 :   } else {
     104               0 :     return -NACL_ABI_EIO;
     105                 :   }
     106                 : }
     107                 : 
     108                 : static void AddIovEntry(void* base,
     109                 :                         size_t length,
     110                 :                         size_t max_iov_len,
     111                 :                         struct NaClImcMsgIoVec* iov,
     112                 :                         size_t* iov_len,
     113             990 :                         size_t* total_bytes) {
     114             990 :   if (length == 0) {
     115               1 :     return;
     116                 :   }
     117             989 :   if (*iov_len >= max_iov_len) {
     118               0 :     return;
     119                 :   }
     120             989 :   iov[*iov_len].base = base;
     121             989 :   iov[*iov_len].length = length;
     122             989 :   ++*iov_len;
     123             989 :   *total_bytes += length;
     124                 : }
     125                 : 
     126             308 : static nacl_abi_size_t VectorLen(NaClSrpcArg** vec) {
     127             308 :   nacl_abi_size_t len = 0;
     128             629 :   for (len = 0; len <= NACL_SRPC_MAX_ARGS; ++len) {
     129             629 :     if (vec[len] == NULL) {
     130             308 :       return len;
     131                 :     }
     132                 :   }
     133               0 :   return NACL_SRPC_MAX_ARGS;
     134                 : }
     135                 : 
     136             134 : static size_t ArrayElementSize(NaClSrpcArg* arg) {
     137             134 :   switch (arg->tag) {
     138                 :     case NACL_SRPC_ARG_TYPE_BOOL:
     139                 :     case NACL_SRPC_ARG_TYPE_DOUBLE:
     140                 :     case NACL_SRPC_ARG_TYPE_HANDLE:
     141                 :     case NACL_SRPC_ARG_TYPE_INT:
     142                 :     case NACL_SRPC_ARG_TYPE_INVALID:
     143                 :     case NACL_SRPC_ARG_TYPE_LONG:
     144                 :     case NACL_SRPC_ARG_TYPE_OBJECT:
     145                 :     case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
     146                 :       /* These are all scalar types. */
     147              66 :       return 0;
     148                 : 
     149                 :     case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
     150              51 :       return sizeof *arg->arrays.carr;
     151                 :     case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
     152               2 :       return sizeof *arg->arrays.darr;
     153                 :     case NACL_SRPC_ARG_TYPE_INT_ARRAY:
     154               6 :       return sizeof *arg->arrays.iarr;
     155                 :     case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
     156               2 :       return sizeof *arg->arrays.larr;
     157                 :     case NACL_SRPC_ARG_TYPE_STRING:
     158               7 :       return sizeof *arg->arrays.str;
     159                 :   }
     160                 :   /* UNREACHED */
     161               0 :   return 0;
     162                 : }
     163                 : 
     164                 : static void ClearTemplateStringLengths(NaClSrpcArg** vec,
     165              18 :                                        size_t vec_len) {
     166                 :   size_t i;
     167              31 :   for (i = 0; i < vec_len; ++i) {
     168              13 :     if (vec[i]->tag == NACL_SRPC_ARG_TYPE_STRING) {
     169               0 :       vec[i]->u.count = 0;
     170                 :     }
     171                 :   }
     172              18 : }
     173                 : 
     174                 : /*
     175                 :  * Adds the IOV entries for the fixed portion of the arguments in vec.
     176                 :  */
     177                 : static void AddFixed(NaClSrpcArg** vec,
     178                 :                      size_t vec_len,
     179                 :                      size_t max_iov_len,
     180                 :                      struct NaClImcMsgIoVec* iov,
     181                 :                      size_t* iov_len,
     182             380 :                      size_t* expected_bytes) {
     183                 :   size_t i;
     184             733 :   for (i = 0; i < vec_len; ++i) {
     185             353 :     AddIovEntry(vec[i], kArgSize, max_iov_len, iov, iov_len, expected_bytes);
     186                 :   }
     187             380 : }
     188                 : 
     189                 : /*
     190                 :  * Copies the handles/descriptors from descs into the appropriately typed
     191                 :  * elements of vec.
     192                 :  */
     193                 : static BoolValue GetHandles(NaClSrpcArg** vec,
     194                 :                             size_t vec_len,
     195                 :                             NaClSrpcImcDescType* descs,
     196             114 :                             size_t desc_len) {
     197                 :   size_t i;
     198             114 :   size_t handle_index = 0;
     199             218 :   for (i = 0; i < vec_len; ++i) {
     200             104 :     if (vec[i]->tag != NACL_SRPC_ARG_TYPE_HANDLE) {
     201             100 :       continue;
     202                 :     }
     203               4 :     if (handle_index >= desc_len) {
     204               0 :       return BoolFalse;
     205                 :     }
     206               4 :     vec[i]->u.hval = descs[handle_index];
     207               4 :     ++handle_index;
     208                 :   }
     209             114 :   return BoolTrue;
     210                 : }
     211                 : 
     212                 : /*
     213                 :  * Reads the header of the message to determine whether to call RecvRequest or
     214                 :  * RecvResponse.
     215                 :  */
     216                 : static ssize_t SrpcPeekMessage(struct NaClSrpcMessageChannel* channel,
     217             122 :                                NaClSrpcRpc* rpc) {
     218                 :   struct NaClImcMsgIoVec iov[1];
     219             122 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     220                 :   size_t iov_len;
     221                 :   NaClSrpcMessageHeader header;
     222                 :   size_t expected_bytes;
     223                 :   ssize_t retval;
     224                 : 
     225             122 :   iov_len = 0;
     226             122 :   expected_bytes = 0;
     227             122 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     228             122 :   header.iov = iov;
     229             122 :   header.iov_length = NACL_ARRAY_SIZE(iov);
     230             122 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
     231             122 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
     232             122 :   retval = NaClSrpcMessageChannelPeek(channel, &header);
     233                 :   /*
     234                 :    * Check that the peek read the RPC and that the argument lengths are sane.
     235                 :    */
     236             122 :   if (retval < (ssize_t) expected_bytes) {
     237               8 :     retval = ErrnoFromImcRet(retval);
     238                 :   }
     239             114 :   else if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
     240                 :            rpc->template_len > NACL_SRPC_MAX_ARGS) {
     241               0 :     retval = -NACL_ABI_EIO;
     242                 :   }
     243             122 :   return retval;
     244                 : }
     245                 : 
     246                 : /*
     247                 :  * Adds the IOV entries for the nonfixed portions of an argument vector to
     248                 :  * read.  For receiving requests we need to allocate memory for the nonfixed
     249                 :  * portions of both the inputs and results, but we do not read the results
     250                 :  * vector's nonfixed portion.  For receiving responses we do not allocate
     251                 :  * memory for the nonfixed portion (the caller has already done that), but we
     252                 :  * read the nonfixed portion of results.
     253                 :  * If it returns BoolFalse, some memory may have been allocated.  It is the
     254                 :  * caller's responsibility to clean up in that case.
     255                 :  */
     256                 : static BoolValue AddNonfixedForRead(NaClSrpcArg** vec,
     257                 :                                     size_t vec_len,
     258                 :                                     size_t max_iov_len,
     259                 :                                     BoolValue alloc_value,
     260                 :                                     BoolValue read_value,
     261                 :                                     struct NaClImcMsgIoVec* iov,
     262                 :                                     size_t* iov_len,
     263             132 :                                     size_t* expected_bytes) {
     264                 :   size_t i;
     265                 : 
     266                 :   /* Initialize the array pointers to allow cleanup if errors happen. */
     267             132 :   if (alloc_value) {
     268              52 :     for (i = 0; i < vec_len; ++i) {
     269              16 :       vec[i]->arrays.oval = NULL;
     270                 :     }
     271                 :   }
     272                 : 
     273             249 :   for (i = 0; i < vec_len; ++i) {
     274             117 :     size_t count = vec[i]->u.count;
     275             117 :     void* base = 0;
     276             117 :     size_t element_size = ArrayElementSize(vec[i]);
     277                 : 
     278             117 :     if (element_size == 0) {
     279                 :       /* Skip fixed size arguments. */
     280              66 :       continue;
     281                 :     }
     282              51 :     if (SIZE_T_MAX / element_size < count) {
     283               0 :       return BoolFalse;
     284                 :     }
     285              51 :     base = vec[i]->arrays.oval;
     286              51 :     if (alloc_value) {
     287              10 :       base = malloc(element_size * count);
     288              10 :       if (base == 0) {
     289               0 :         return BoolFalse;
     290                 :       }
     291              10 :       vec[i]->arrays.oval = base;
     292                 :     }
     293              51 :     if (read_value) {
     294              42 :       AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
     295                 :                   expected_bytes);
     296                 :     }
     297                 :   }
     298             132 :   return BoolTrue;
     299                 : }
     300                 : 
     301             132 : static BoolValue AllocateArgs(NaClSrpcArg** arg_pointers, size_t length) {
     302                 :   NaClSrpcArg* arg_array;
     303                 :   nacl_abi_size_t i;
     304                 : 
     305                 :   /* Initialize the array pointers to allow cleanup if errors happen. */
     306             381 :   for (i = 0; i < length + 1; ++i) {
     307             249 :     arg_pointers[i] = NULL;
     308                 :   }
     309             132 :   if (length == 0) {
     310              35 :     return BoolTrue;
     311                 :   }
     312                 : 
     313              97 :   if (SIZE_T_MAX / sizeof **arg_pointers < length) {
     314               0 :     return BoolFalse;
     315                 :   }
     316              97 :   arg_array = (NaClSrpcArg*) malloc(length * sizeof **arg_pointers);
     317              97 :   if (arg_array == NULL) {
     318               0 :     return BoolFalse;
     319                 :   }
     320                 :   /* Initialize the individual args. */
     321             214 :   for (i = 0; i < length; ++i) {
     322             117 :     NaClSrpcArgCtor(&arg_array[i]);
     323                 :   }
     324                 :   /* Set each array pointer to point to the respective arg. */
     325             214 :   for (i = 0; i < length; ++i) {
     326             117 :     arg_pointers[i] = &arg_array[i];
     327                 :   }
     328              97 :   return BoolTrue;
     329                 : }
     330                 : 
     331             168 : static void FreeArgs(NaClSrpcArg** vec) {
     332                 :   nacl_abi_size_t i;
     333                 :   NaClSrpcArg* args;
     334                 : 
     335             168 :   if (vec == NULL) {
     336              36 :     return;
     337                 :   }
     338             132 :   args = vec[0];
     339                 : 
     340             249 :   for (i = 0; i <= NACL_SRPC_MAX_ARGS; ++i) {
     341             249 :     if (vec[i] == NULL) {
     342             132 :       break;
     343                 :     }
     344             117 :     switch (vec[i]->tag) {
     345                 :       case NACL_SRPC_ARG_TYPE_BOOL:
     346                 :       case NACL_SRPC_ARG_TYPE_DOUBLE:
     347                 :       case NACL_SRPC_ARG_TYPE_HANDLE:
     348                 :       case NACL_SRPC_ARG_TYPE_INT:
     349                 :       case NACL_SRPC_ARG_TYPE_INVALID:
     350                 :       case NACL_SRPC_ARG_TYPE_LONG:
     351                 :       case NACL_SRPC_ARG_TYPE_OBJECT:
     352                 :       case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
     353              66 :         break;
     354                 : 
     355                 :       case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
     356                 :       case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
     357                 :       case NACL_SRPC_ARG_TYPE_INT_ARRAY:
     358                 :       case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
     359                 :       case NACL_SRPC_ARG_TYPE_STRING:
     360              51 :         free(vec[i]->arrays.oval);
     361                 :         break;
     362                 :     }
     363             117 :     vec[i] = NULL;
     364                 :   }
     365             132 :   free(args);
     366                 : }
     367                 : 
     368                 : static ssize_t RecvRequest(struct NaClSrpcMessageChannel* channel,
     369                 :                            NaClSrpcRpc* rpc,
     370                 :                            NaClSrpcArg** inputs,
     371              18 :                            NaClSrpcArg** results) {
     372                 :   struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
     373              18 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     374                 :   size_t iov_len;
     375                 :   NaClSrpcMessageHeader header;
     376                 :   NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
     377                 :   size_t expected_bytes;
     378                 :   ssize_t retval;
     379                 : 
     380                 :   /*
     381                 :    * SrpcPeekMessage should have been called before this function, and should
     382                 :    * have populated rpc.  Make sure that rpc points to a sane header.
     383                 :    */
     384              18 :   if (!rpc->is_request ||
     385                 :       rpc->template_len > NACL_SRPC_MAX_ARGS ||
     386                 :       rpc->value_len > NACL_SRPC_MAX_ARGS) {
     387               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     388                 :                 "RecvRequest: rpc header invalid: is_request %"NACL_PRIu32", "
     389                 :                 "template_len %"NACL_PRIu32", value_len %"NACL_PRIu32"\n",
     390                 :                 rpc->is_request,
     391                 :                 rpc->template_len,
     392                 :                 rpc->value_len);
     393               0 :     retval = -NACL_ABI_EINVAL;
     394               0 :     goto done;
     395                 :   }
     396                 :   /*
     397                 :    * A request will contain two vectors of NaClSrpcArgs.  Set the index
     398                 :    * pointers passed in to new argument vectors that will be filled during
     399                 :    * the next peek.
     400                 :    */
     401              18 :   if (!AllocateArgs(results, rpc->template_len) ||
     402                 :       !AllocateArgs(inputs, rpc->value_len)) {
     403               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     404                 :                 "RecvRequest: AllocateArgs failed\n");
     405               0 :     retval = -NACL_ABI_EINVAL;
     406               0 :     goto done;
     407                 :   }
     408                 : 
     409                 :   /*
     410                 :    * Having read the header we know how many elements each argument vector
     411                 :    * contains.  The next peek reads the fixed portion of these argument vectors,
     412                 :    * but cannot yet read the variable length portion, because we do not yet
     413                 :    * know the counts of array types or strings.
     414                 :    */
     415              18 :   iov_len = 0;
     416              18 :   expected_bytes = 0;
     417              18 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     418              18 :   AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
     419                 :            &expected_bytes);
     420              18 :   AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     421              18 :   header.iov = iov;
     422              18 :   header.iov_length = (nacl_abi_size_t) iov_len;
     423              18 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
     424              18 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
     425              18 :   retval = NaClSrpcMessageChannelPeek(channel, &header);
     426              18 :   if (retval < (ssize_t) expected_bytes) {
     427               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     428                 :                 "RecvRequest:"
     429                 :                 "NaClSrpcMessageChannelPeek incomplete: expected %"
     430                 :                 NACL_PRIdS", got %"NACL_PRIdS"\n",
     431                 :                 expected_bytes,
     432                 :                 retval);
     433               0 :     retval = ErrnoFromImcRet(retval);
     434               0 :     goto done;
     435                 :   }
     436                 : 
     437                 :   /*
     438                 :    * After peeking the fixed portion of the argument vectors we are ready to
     439                 :    * read the nonfixed portions as well.  So the read just adds the IOV entries
     440                 :    * for the nonfixed portions of the arguments.
     441                 :    */
     442              18 :   iov_len = 0;
     443              18 :   expected_bytes = 0;
     444              18 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     445              18 :   ClearTemplateStringLengths(results, rpc->template_len);
     446              18 :   AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
     447                 :            &expected_bytes);
     448              18 :   AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     449              18 :   if (!AddNonfixedForRead(results, rpc->template_len, kMaxIovLen,
     450                 :                           1, 0, iov, &iov_len, &expected_bytes)) {
     451               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     452                 :                 "RecvRequest: AllocateArgs failed for results\n");
     453               0 :     retval = -NACL_ABI_EIO;
     454               0 :     goto done;
     455                 :   }
     456              18 :   if (!AddNonfixedForRead(inputs, rpc->value_len, kMaxIovLen,
     457                 :                           1, 1, iov, &iov_len, &expected_bytes)) {
     458               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     459                 :                 "RecvRequest: AllocateArgs failed for inputs\n");
     460               0 :     retval = -NACL_ABI_EIO;
     461               0 :     goto done;
     462                 :   }
     463              18 :   header.iov = iov;
     464              18 :   header.iov_length = (nacl_abi_size_t) iov_len;
     465              18 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
     466              18 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
     467              18 :   retval = NaClSrpcMessageChannelReceive(channel, &header);
     468              18 :   if (retval < (ssize_t) expected_bytes) {
     469               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     470                 :                 "RecvRequest:"
     471                 :                 " NaClSrpcMessageChannelReceive incomplete: expected %"
     472                 :                 NACL_PRIdS", got %"NACL_PRIdS"\n",
     473                 :                 expected_bytes,
     474                 :                 retval);
     475               0 :     retval = ErrnoFromImcRet(retval);
     476               0 :     goto done;
     477                 :   }
     478                 : 
     479                 :   /*
     480                 :    * The read left any descriptors passed in the descs array.  We need to
     481                 :    * copy those descriptors to the inputs vector.
     482                 :    */
     483              18 :   if (!GetHandles(inputs, rpc->value_len,
     484                 :                   descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     485               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     486                 :                 "RecvRequest: GetHandles failed\n");
     487               0 :     retval = -NACL_ABI_EIO;
     488               0 :     goto done;
     489                 :   }
     490                 :   /*
     491                 :    * Success, the caller has taken ownership of the memory we allocated
     492                 :    * for inputs and results.
     493                 :    */
     494              18 :   inputs = NULL;
     495              18 :   results = NULL;
     496                 : 
     497              18 :  done:
     498              18 :   FreeArgs(inputs);
     499              18 :   FreeArgs(results);
     500              18 :   return retval;
     501                 : }
     502                 : 
     503                 : /*
     504                 :  * Checks for type conformance between a peeked results vector and the caller's
     505                 :  * results vector.  If the types agree then nonfixed sizes are checked to
     506                 :  * ensure that the caller's buffers are large enough to receive the peeked
     507                 :  * nonfixed size objects.  If this agrees, then the caller's size is updated
     508                 :  * to reflect how many elements were actually received.
     509                 :  */
     510                 : static BoolValue CheckMatchAndCopyCounts(size_t vec_len,
     511                 :                                          NaClSrpcArg** expected,
     512              96 :                                          NaClSrpcArg** peeked) {
     513                 :   size_t i;
     514                 : 
     515             197 :   for (i = 0; i < vec_len; ++i) {
     516             101 :     if (expected[i]->tag != peeked[i]->tag) {
     517               0 :       return BoolFalse;
     518                 :     }
     519             101 :     switch (expected[i]->tag) {
     520                 :       case NACL_SRPC_ARG_TYPE_BOOL:
     521                 :       case NACL_SRPC_ARG_TYPE_DOUBLE:
     522                 :       case NACL_SRPC_ARG_TYPE_HANDLE:
     523                 :       case NACL_SRPC_ARG_TYPE_INT:
     524                 :       case NACL_SRPC_ARG_TYPE_INVALID:
     525                 :       case NACL_SRPC_ARG_TYPE_LONG:
     526                 :       case NACL_SRPC_ARG_TYPE_OBJECT:
     527                 :       case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
     528              60 :         break;
     529                 : 
     530                 :       case NACL_SRPC_ARG_TYPE_STRING:
     531                 :         /*
     532                 :          * Returned strings are allocated by the SRPC transport mechanism,
     533                 :          * whereas all the other "array" types are allocated by the caller
     534                 :          * of the respective Invoke routine.
     535                 :          */
     536               7 :         expected[i]->arrays.oval = malloc(peeked[i]->u.count);
     537               7 :         if (expected[i]->arrays.oval == NULL) {
     538               0 :           return BoolFalse;
     539                 :         }
     540               7 :         expected[i]->u.count = peeked[i]->u.count;
     541               7 :         break;
     542                 : 
     543                 :       case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
     544                 :       case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
     545                 :       case NACL_SRPC_ARG_TYPE_INT_ARRAY:
     546                 :       case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
     547              34 :         if (peeked[i]->u.count > expected[i]->u.count) {
     548               0 :           return BoolFalse;
     549                 :         }
     550              34 :         expected[i]->u.count = peeked[i]->u.count;
     551                 :         break;
     552                 :     }
     553                 :   }
     554              96 :   return BoolTrue;
     555                 : }
     556                 : 
     557                 : static ssize_t RecvResponse(struct NaClSrpcMessageChannel* channel,
     558                 :                             NaClSrpcRpc* rpc,
     559              96 :                             NaClSrpcArg** results) {
     560                 :   NaClSrpcArg* result_copy[NACL_SRPC_MAX_ARGS + 1];
     561                 :   struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
     562              96 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     563              96 :   size_t iov_len = 0;
     564                 :   NaClSrpcMessageHeader header;
     565                 :   NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
     566                 :   size_t expected_bytes;
     567                 :   ssize_t retval;
     568                 :   size_t i;
     569                 : 
     570              96 :   if (results == NULL) {
     571               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     572                 :                 "RecvResponse: results should not be NULL\n");
     573               0 :     retval = -NACL_ABI_EINVAL;
     574               0 :     goto done;
     575                 :   }
     576                 :   /*
     577                 :    * SrpcPeekMessage should have been called before this function, and should
     578                 :    * have populated rpc.  Make sure that rpc points to a sane header.
     579                 :    */
     580              96 :   if (rpc->is_request ||
     581                 :       rpc->template_len > 0 ||
     582                 :       rpc->value_len > NACL_SRPC_MAX_ARGS ||
     583                 :       rpc->value_len != VectorLen(results)) {
     584               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     585                 :                 "RecvResponse: rpc header invalid: is_request %"NACL_PRIu32", "
     586                 :                 "template_len %"NACL_PRIu32", value_len %"NACL_PRIu32"\n",
     587                 :                 rpc->is_request,
     588                 :                 rpc->template_len,
     589                 :                 rpc->value_len);
     590               0 :     return -NACL_ABI_EINVAL;
     591                 :   }
     592                 : 
     593                 :   /*
     594                 :    * Having read the header we know how many elements the results vector
     595                 :    * contains.  The next peek reads the fixed portion of the results vectors,
     596                 :    * but cannot yet read the variable length portion, because we do not yet
     597                 :    * know the counts of array types or strings.  Because the results read
     598                 :    * could conflict with the expected types, we need to read the fixed portion
     599                 :    * into a copy.
     600                 :    */
     601              96 :   if (!AllocateArgs(result_copy, rpc->value_len)) {
     602               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     603                 :                 "RecvResponse: AllocateArgs failed\n");
     604               0 :     retval = -NACL_ABI_EINVAL;
     605               0 :     goto done;
     606                 :   }
     607              96 :   iov_len = 0;
     608              96 :   expected_bytes = 0;
     609              96 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     610             197 :   for (i = 0; i < rpc->value_len; ++i) {
     611             101 :     AddIovEntry(result_copy[i], kArgSize, kMaxIovLen, iov, &iov_len,
     612                 :                 &expected_bytes);
     613                 :   }
     614              96 :   header.iov = iov;
     615              96 :   header.iov_length = (nacl_abi_size_t) iov_len;
     616              96 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
     617              96 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
     618              96 :   retval = NaClSrpcMessageChannelPeek(channel, &header);
     619              96 :   if (retval < (ssize_t) expected_bytes) {
     620               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     621                 :                 "RecvResponse: NaClSrpcMessageChannelPeek incomplete: "
     622                 :                 "expected %"NACL_PRIdS", got %"NACL_PRIdS"\n",
     623                 :                 expected_bytes,
     624                 :                 retval);
     625               0 :     retval = ErrnoFromImcRet(retval);
     626               0 :     goto done;
     627                 :   }
     628                 : 
     629                 :   /*
     630                 :    * Check that the peeked results vector's types conform to the types passed
     631                 :    * in and that any nonfixed size arguments are no larger than the counts
     632                 :    * passed in from the caller.  If the values are acceptable, we copy the
     633                 :    * actual sizes to the caller's vector.
     634                 :    */
     635              96 :   if (!CheckMatchAndCopyCounts(rpc->value_len, results, result_copy)) {
     636               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     637                 :                 "RecvResponse: CheckMatchAndCopyCounts failed\n");
     638               0 :     retval = -NACL_ABI_EIO;
     639               0 :     goto done;
     640                 :   }
     641                 : 
     642                 :   /*
     643                 :    * After peeking the fixed portion of the results vector we are ready to
     644                 :    * read the nonfixed portion as well.  So the read just adds the IOV entries
     645                 :    * for the nonfixed portion of results.
     646                 :    */
     647              96 :   iov_len = 0;
     648              96 :   expected_bytes = 0;
     649              96 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     650              96 :   AddFixed(results, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     651              96 :   if (!AddNonfixedForRead(results, rpc->value_len, kMaxIovLen,
     652                 :                           0, 1, iov, &iov_len, &expected_bytes)) {
     653               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     654                 :                 "RecvResponse: AddNonfixedForRead failed\n");
     655               0 :     retval = -NACL_ABI_EIO;
     656               0 :     goto done;
     657                 :   }
     658              96 :   header.iov = iov;
     659              96 :   header.iov_length = (nacl_abi_size_t) iov_len;
     660              96 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
     661              96 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
     662              96 :   retval = NaClSrpcMessageChannelReceive(channel, &header);
     663              96 :   if (retval < (ssize_t) expected_bytes) {
     664               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     665                 :                 "RecvResponse: NaClSrpcMessageChannelReceive incomplete: "
     666                 :                 "expected %"NACL_PRIdS", got %"NACL_PRIdS"\n",
     667                 :                 expected_bytes,
     668                 :                 retval);
     669               0 :     retval = ErrnoFromImcRet(retval);
     670               0 :     goto done;
     671                 :   }
     672                 : 
     673                 :   /*
     674                 :    * The read left any descriptors returned in the descs array.  We need to
     675                 :    * copy those descriptors to the results vector.
     676                 :    */
     677              96 :   if (!GetHandles(results, rpc->value_len,
     678                 :                   descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     679               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     680                 :                 "RecvResponse: GetHandles failed\n");
     681               0 :     retval = -NACL_ABI_EIO;
     682                 :   }
     683                 : 
     684              96 :  done:
     685              96 :   FreeArgs(result_copy);
     686              96 :   return retval;
     687                 : }
     688                 : 
     689                 : /*
     690                 :  * Adds IOV entries for the non-fixed portions of the arguments in vec.
     691                 :  * This could also add handles/descriptors to the array to send.
     692                 :  */
     693                 : static BoolValue AddNonfixedForWrite(NaClSrpcArg** vec,
     694                 :                                      size_t vec_len,
     695                 :                                      size_t max_iov_len,
     696                 :                                      struct NaClImcMsgIoVec* iov,
     697                 :                                      size_t* iov_len,
     698                 :                                      NaClSrpcImcDescType* descs,
     699                 :                                      size_t* desc_len,
     700             115 :                                      size_t* expected_bytes) {
     701                 :   size_t i;
     702                 :   size_t element_size;
     703                 :   nacl_abi_size_t count;
     704                 :   void* base;
     705                 : 
     706                 :   /* Add IOV entries for the array/string types in vec. */
     707             233 :   for (i = 0; i < vec_len; ++i) {
     708             118 :     switch (vec[i]->tag) {
     709                 :       case NACL_SRPC_ARG_TYPE_BOOL:
     710                 :       case NACL_SRPC_ARG_TYPE_DOUBLE:
     711                 :       case NACL_SRPC_ARG_TYPE_INT:
     712                 :       case NACL_SRPC_ARG_TYPE_INVALID:
     713                 :       case NACL_SRPC_ARG_TYPE_LONG:
     714                 :       case NACL_SRPC_ARG_TYPE_OBJECT:
     715                 :       case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
     716                 :        /* Scalar types are handled by fixed iovs alone. */
     717              76 :        break;
     718                 : 
     719                 :       case NACL_SRPC_ARG_TYPE_HANDLE:
     720                 :         /* Handles are added into the desc array. */
     721              13 :         descs[*desc_len] = vec[i]->u.hval;
     722              13 :         ++*desc_len;
     723              13 :         break;
     724                 : 
     725                 :       case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
     726                 :       case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
     727                 :       case NACL_SRPC_ARG_TYPE_INT_ARRAY:
     728                 :       case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
     729              17 :         count = vec[i]->u.count;
     730              17 :         base = vec[i]->arrays.oval;
     731              17 :         element_size = ArrayElementSize(vec[i]);
     732                 :         /* Check that computing the number of bytes will not overflow. */
     733              17 :         if (SIZE_T_MAX / element_size < count) {
     734               0 :           return BoolFalse;
     735                 :         }
     736              17 :         AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
     737                 :                     expected_bytes);
     738              17 :         break;
     739                 : 
     740                 :       case NACL_SRPC_ARG_TYPE_STRING:
     741              12 :         count = (nacl_abi_size_t) strlen(vec[i]->arrays.str) + 1;
     742              12 :         base = vec[i]->arrays.oval;
     743              12 :         vec[i]->u.count = count;
     744              12 :         AddIovEntry(base, count, max_iov_len, iov, iov_len, expected_bytes);
     745                 :         break;
     746                 :     }
     747                 :   }
     748             115 :   return BoolTrue;
     749                 : }
     750                 : 
     751                 : static ssize_t SrpcSendMessage(NaClSrpcRpc* rpc,
     752                 :                                NaClSrpcArg** inputs,
     753                 :                                NaClSrpcArg** results,
     754             115 :                                struct NaClSrpcMessageChannel* channel) {
     755                 :   NaClSrpcArg** values;
     756                 :   struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
     757             115 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     758                 :   size_t iov_len;
     759                 :   NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
     760             115 :   size_t desc_len = 0;
     761                 :   NaClSrpcMessageHeader header;
     762                 :   ssize_t retval;
     763                 :   size_t expected_bytes;
     764                 : 
     765                 :   /*
     766                 :    * The message will be sent in three portions:
     767                 :    * 1) the header (rpc)
     768                 :    * 2) the fixed portions of the inputs and results arrays (inputs may be
     769                 :    *    null for responses)
     770                 :    * 3) the nonfixed portions of the inputs or results array
     771                 :    */
     772             115 :   iov_len = 0;
     773             115 :   expected_bytes = 0;
     774             115 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     775                 : 
     776             115 :   if (rpc->is_request) {
     777                 :     /*
     778                 :      * For requests we pass only the fixed portion of the results vector.
     779                 :      * This is to convey to the invoked procedure the type and size of the
     780                 :      * allowed result values.
     781                 :      * The values to be passed in both fixed and nonfixed are from inputs.
     782                 :      */
     783              97 :     if (results == NULL) {
     784               0 :       rpc->template_len = 0;
     785                 :     } else {
     786              97 :       rpc->template_len = VectorLen(results);
     787              97 :       AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
     788                 :                &expected_bytes);
     789                 :     }
     790              97 :     values = inputs;
     791                 :   } else {
     792                 :     /*
     793                 :      * For responses there are no templates, and the values that will be passed
     794                 :      * are from results.
     795                 :      */
     796              18 :     values = results;
     797              18 :     rpc->template_len = 0;
     798                 :   }
     799                 :   /*
     800                 :    * Pass the fixed and nonfixed portions.
     801                 :    */
     802             115 :   if (values == NULL) {
     803               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     804                 :                 "SrpcSendMessage: values should not be NULL\n");
     805               0 :     return -NACL_ABI_EINVAL;
     806                 :   }
     807             115 :   rpc->value_len = VectorLen(values);
     808             115 :   AddFixed(values, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     809             115 :   if (!AddNonfixedForWrite(values, rpc->value_len,
     810                 :                            kMaxIovLen,
     811                 :                            iov, &iov_len,
     812                 :                            descs, &desc_len,
     813                 :                            &expected_bytes)) {
     814               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     815                 :                 "SrpcSendMessage: AddNonfixedForWrite failed\n");
     816               0 :     return -NACL_ABI_EIO;
     817                 :   }
     818             115 :   header.iov = iov;
     819             115 :   header.iov_length = (nacl_abi_size_t) iov_len;
     820             115 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
     821             115 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) desc_len;
     822             115 :   retval = NaClSrpcMessageChannelSend(channel, &header);
     823             115 :   if (retval >= 0  && retval < (ssize_t) expected_bytes) {
     824               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     825                 :                 "SrpcSendMessage: NaClSrpcMessageChannelSend incomplete: "
     826                 :                 "expected %"NACL_PRIdS", got %"NACL_PRIdS"\n",
     827                 :                 expected_bytes,
     828                 :                 retval);
     829               0 :     return -NACL_ABI_EIO;
     830                 :   }
     831             115 :   return retval;
     832                 : }
     833                 : 
     834                 : /* TODO(sehr): make this public when the client side uses RPC. */
     835             122 : static BoolValue NaClSrpcRpcCtor(NaClSrpcRpc* rpc, NaClSrpcChannel* channel) {
     836             122 :   rpc->channel = channel;
     837             122 :   rpc->result = NACL_SRPC_RESULT_INTERNAL;
     838             122 :   rpc->rets = NULL;
     839             122 :   return BoolTrue;
     840                 : }
     841                 : 
     842                 : /* A self-deleting closure to send responses from RPC servers. */
     843                 : typedef struct RpcCheckingClosure {
     844                 :   struct NaClSrpcClosure base;
     845                 :   NaClSrpcRpc* rpc;
     846                 : } RpcCheckingClosure;
     847                 : 
     848              18 : static void RpcCheckingClosureRun(NaClSrpcClosure* self) {
     849              18 :   RpcCheckingClosure* vself = (RpcCheckingClosure*) self;
     850              18 :   NaClSrpcRpc* rpc = vself->rpc;
     851                 :   ssize_t retval;
     852                 : 
     853                 :   do {
     854                 :     const char* rpc_name;
     855                 :     const char* arg_types;
     856                 :     const char* ret_types;
     857                 :     int i;
     858              18 :     NaClSrpcServiceMethodNameAndTypes(rpc->channel->server,
     859                 :                                       rpc->rpc_number,
     860                 :                                       &rpc_name,
     861                 :                                       &arg_types,
     862                 :                                       &ret_types);
     863              18 :     NaClSrpcLog(1,
     864                 :                 "RpcCheckingClosureRun: response(channel=%p,"
     865                 :                 " rpc_number=%"NACL_PRIu32
     866                 :                 ", rpc_name=\"%s\", result=%d, string=\"%s\")\n",
     867                 :                 (void*) rpc->channel,
     868                 :                 rpc->rpc_number,
     869                 :                 rpc_name,
     870                 :                 rpc->result,
     871                 :                 NaClSrpcErrorString(rpc->result));
     872              31 :     for (i = 0; rpc->rets[i] != NULL; i++ ) {
     873                 :       char buffer[256];
     874              13 :       NaClSrpcFormatArg(2, rpc->rets[i], buffer, NACL_ARRAY_SIZE(buffer));
     875              13 :       NaClSrpcLog(2,
     876                 :                   "RpcCheckingClosureRun: response(channel=%p, rets[%d]=%s)\n",
     877                 :                   (void*) rpc->channel,
     878                 :                   i,
     879                 :                   buffer);
     880                 :     }
     881                 :   } while(0);
     882                 :   /* Send the RPC response to the caller. */
     883              18 :   rpc->is_request = 0;
     884              18 :   rpc->dispatch_loop_should_continue = 1;
     885              18 :   if (NACL_SRPC_RESULT_BREAK == rpc->result) {
     886               0 :     NaClSrpcLog(2,
     887                 :                 "RpcCheckingClosureRun: server requested break\n");
     888               0 :     rpc->result = NACL_SRPC_RESULT_OK;
     889               0 :     rpc->dispatch_loop_should_continue = 0;
     890                 :   }
     891              18 :   retval = SrpcSendMessage(rpc, NULL, rpc->rets, rpc->channel->message_channel);
     892              18 :   if (retval < 0) {
     893                 :     /* If the response write failed, drop request and continue. */
     894               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     895                 :                 "RpcCheckingClosureRun: response write failed\n");
     896                 :   }
     897              18 :   free(self);
     898              18 : }
     899                 : 
     900                 : static BoolValue RpcCheckingClosureCtor(RpcCheckingClosure* self,
     901             122 :                                         NaClSrpcRpc* rpc) {
     902             122 :   self->base.Run = RpcCheckingClosureRun;
     903             122 :   self->rpc = rpc;
     904             122 :   self->rpc->dispatch_loop_should_continue = 1;
     905             122 :   return BoolTrue;
     906                 : }
     907                 : 
     908                 : static BoolValue RequestVectorTypesConform(NaClSrpcChannel* channel,
     909                 :                                            NaClSrpcRpc* rpc,
     910                 :                                            NaClSrpcArg** args,
     911              18 :                                            NaClSrpcArg** rets) {
     912                 :   const char* rpc_name;
     913                 :   const char* arg_types;
     914                 :   const char* ret_types;
     915                 :   ssize_t retval;
     916                 :   size_t i;
     917                 : 
     918              18 :   if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
     919                 :       rpc->template_len > NACL_SRPC_MAX_ARGS) {
     920               0 :     return BoolFalse;
     921                 :   }
     922                 :   /* Get service discovery's remembered types for args and rets */
     923              18 :   retval = NaClSrpcServiceMethodNameAndTypes(channel->server,
     924                 :                                              rpc->rpc_number,
     925                 :                                              &rpc_name,
     926                 :                                              &arg_types,
     927                 :                                              &ret_types);
     928              18 :   if (!retval) {
     929               0 :     return BoolFalse;
     930                 :   }
     931                 :   /* Check that lengths match. */
     932              18 :   if (rpc->value_len != strlen(arg_types) ||
     933                 :       rpc->template_len != strlen(ret_types)) {
     934               0 :     return BoolFalse;
     935                 :   }
     936                 :   /* Check args for type conformance. */
     937              21 :   for (i = 0; i < rpc->value_len; ++i) {
     938               3 :     if (args[i] == NULL) {
     939               0 :       return BoolFalse;
     940                 :     }
     941               3 :     if (args[i]->tag != (unsigned char) arg_types[i]) {
     942               0 :       return BoolFalse;
     943                 :     }
     944                 :   }
     945              18 :   if (args[rpc->value_len] != NULL) {
     946               0 :     return BoolFalse;
     947                 :   }
     948                 :   /* Check rets for type conformance. */
     949              31 :   for (i = 0; i < rpc->template_len; ++i) {
     950              13 :     if (rets[i] == NULL) {
     951               0 :       return BoolFalse;
     952                 :     }
     953              13 :     if (rets[i]->tag != (unsigned char) ret_types[i]) {
     954               0 :       return BoolFalse;
     955                 :     }
     956                 :   }
     957              18 :   if (rets[rpc->template_len] != NULL) {
     958               0 :     return BoolFalse;
     959                 :   }
     960              18 :   return BoolTrue;
     961                 : }
     962                 : 
     963                 : /*
     964                 :  * The receive/dispatch function returns an enum indicating how the enclosing
     965                 :  * loop should proceed.
     966                 :  */
     967                 : typedef enum {
     968                 :   DISPATCH_CONTINUE,  /* Continue receive-dispatch loop */
     969                 :   DISPATCH_BREAK,     /* Break out of loop was requested by invoked method */
     970                 :   DISPATCH_RESPONSE,  /* Instead of a request, we received a response */
     971                 :   DISPATCH_EOF        /* No more requests or responses can be received */
     972                 : } DispatchReturn;
     973                 : 
     974                 : static DispatchReturn NaClSrpcReceiveAndDispatch(NaClSrpcChannel* channel,
     975             122 :                                                  NaClSrpcRpc* rpc_stack_top) {
     976                 :   NaClSrpcRpc rpc;
     977                 :   NaClSrpcArg* args[NACL_SRPC_MAX_ARGS + 1];
     978                 :   NaClSrpcArg* rets[NACL_SRPC_MAX_ARGS + 1];
     979                 :   NaClSrpcMethod method;
     980                 :   ssize_t bytes_read;
     981             122 :   RpcCheckingClosure* closure = NULL;
     982                 :   /* DISPATCH_EOF is the closest we have to an error return. */
     983             122 :   DispatchReturn dispatch_return = DISPATCH_EOF;
     984                 : 
     985             122 :   closure = (RpcCheckingClosure*) malloc(sizeof *closure);
     986             122 :   if (NULL == closure) {
     987               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     988                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
     989                 :                 "closure malloc failed\n",
     990                 :                 (void*) channel);
     991               0 :     dispatch_return = DISPATCH_EOF;
     992               0 :     goto done;
     993                 :   }
     994             122 :   if (!NaClSrpcRpcCtor(&rpc, channel) ||
     995                 :       !RpcCheckingClosureCtor(closure, &rpc)) {
     996               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     997                 :                 "NaClSrpcReceiveAndDispatch(channel=%p): constructor failed\n",
     998                 :                 (void*) channel);
     999               0 :     goto done;
    1000                 :   }
    1001             122 :   rpc.rets = rets;
    1002                 :   /* Read a message from the channel. */
    1003             122 :   bytes_read = SrpcPeekMessage(channel->message_channel, &rpc);
    1004             122 :   if (bytes_read < 0) {
    1005               8 :     goto done;
    1006                 :   }
    1007             114 :   if (rpc.is_request) {
    1008                 :     /* This is a new request. */
    1009              18 :     if (NULL == channel->server) {
    1010               0 :       if (NULL == rpc_stack_top) {
    1011                 :         /* There is no service to dispatch requests. Abort. */
    1012               0 :         dispatch_return = DISPATCH_EOF;
    1013               0 :         goto done;
    1014                 :       } else {
    1015                 :         /* Inform the pending invoke that a failure happened. */
    1016               0 :         NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1017                 :                     "NaClSrpcReceiveAndDispatch(channel=%p):"
    1018                 :                     "out of order request\n",
    1019                 :                     (void*) channel);
    1020               0 :         rpc_stack_top->result = NACL_SRPC_RESULT_INTERNAL;
    1021               0 :         dispatch_return = DISPATCH_BREAK;
    1022               0 :         goto done;
    1023                 :       }
    1024                 :     }
    1025                 :     /* Fall through to request handling below. */
    1026                 :   } else {
    1027                 :     /* This is a response to a pending request. */
    1028              96 :     if (NULL == rpc_stack_top) {
    1029               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1030                 :                   "NaClSrpcReceiveAndDispatch(channel=%p):"
    1031                 :                   "response, no pending request\n",
    1032                 :                   (void*) channel);
    1033                 :       /* There is no pending request. Abort. */
    1034               0 :       dispatch_return = DISPATCH_BREAK;
    1035               0 :       goto done;
    1036                 :     } else {
    1037              96 :       if (rpc.request_id == rpc_stack_top->request_id) {
    1038                 :         /* Copy the serialized portion of the Rpc and process as a response. */
    1039              96 :         memcpy(rpc_stack_top, &rpc, kRpcSize);
    1040              96 :         dispatch_return = DISPATCH_RESPONSE;
    1041              96 :         goto done;
    1042                 :       } else {
    1043                 :         /* Received an out-of-order response.  Abort. */
    1044               0 :         NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1045                 :                     "NaClSrpcReceiveAndDispatch(channel=%p):"
    1046                 :                     " response for wrong request\n",
    1047                 :                     (void*) channel);
    1048               0 :         dispatch_return = DISPATCH_BREAK;
    1049               0 :         goto done;
    1050                 :       }
    1051                 :     }
    1052                 :   }
    1053              18 :   bytes_read = RecvRequest(channel->message_channel, &rpc, args, rets);
    1054              18 :   if (bytes_read < 0) {
    1055               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1056                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1057                 :                 "RecvRequest failed, bytes=%"NACL_PRIdS"\n",
    1058                 :                 (void*) channel,
    1059                 :                 bytes_read);
    1060               0 :     dispatch_return = DISPATCH_EOF;
    1061                 :   }
    1062              18 :   if (!RequestVectorTypesConform(channel, &rpc, args, rets)) {
    1063               0 :     NaClSrpcLog(NACL_SRPC_LOG_WARNING,
    1064                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1065                 :                 " arg/ret type mismatch (recoverable error)\n",
    1066                 :                 (void*) channel);
    1067               0 :     dispatch_return = DISPATCH_CONTINUE;
    1068               0 :     goto done;
    1069                 :   }
    1070                 :   /* Then we invoke the method, which computes a return code. */
    1071              18 :   method = NaClSrpcServiceMethod(channel->server, rpc.rpc_number);
    1072              18 :   if (NULL == method) {
    1073               0 :     NaClSrpcLog(NACL_SRPC_LOG_WARNING,
    1074                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1075                 :                 " bad rpc_number %"NACL_PRIu32" (recoverable error)\n",
    1076                 :                 (void*) channel,
    1077                 :                 rpc.rpc_number);
    1078               0 :     dispatch_return = DISPATCH_CONTINUE;
    1079               0 :     goto done;
    1080                 :   }
    1081                 :   do {
    1082                 :     const char* rpc_name;
    1083                 :     const char* arg_types;
    1084                 :     const char* ret_types;
    1085                 :     int i;
    1086              18 :     NaClSrpcServiceMethodNameAndTypes(channel->server,
    1087                 :                                       rpc.rpc_number,
    1088                 :                                       &rpc_name,
    1089                 :                                       &arg_types,
    1090                 :                                       &ret_types);
    1091              18 :     NaClSrpcLog(1, "NaClSrpcReceiveAndDispatch:"
    1092                 :                 " request(channel=%p, rpc_number=%"NACL_PRIu32
    1093                 :                 ", rpc_name=\"%s\")\n",
    1094                 :                 (void*) channel,
    1095                 :                 rpc.rpc_number,
    1096                 :                 rpc_name);
    1097              21 :     for (i = 0; args[i] != NULL; i++ ) {
    1098                 :       char buffer[256];
    1099               3 :       NaClSrpcFormatArg(2, args[i], buffer, NACL_ARRAY_SIZE(buffer));
    1100               3 :       NaClSrpcLog(2,
    1101                 :                   "NaClSrpcReceiveAndDispatch:"
    1102                 :                   " request(channel=%p, args[%d]=%s)\n",
    1103                 :                   (void*) channel,
    1104                 :                   i,
    1105                 :                   buffer);
    1106                 :     }
    1107                 :   } while(0);
    1108              18 :   (*method)(&rpc, args, rets, (NaClSrpcClosure*) closure);
    1109              18 :   FreeArgs(args);
    1110              18 :   FreeArgs(rets);
    1111                 :   /* The invoked method takes ownership of the closure and deletes it. */
    1112              18 :   closure = NULL;
    1113                 :   /*
    1114                 :    * Return code to either continue or break out of the processing loop.
    1115                 :    * When we separate closure invocation from the dispatch loop we will
    1116                 :    * have to implement a barrier to make sure that all preceding RPCs are
    1117                 :    * completed, and then signal the dispatcher to stop.
    1118                 :    */
    1119              18 :   if (rpc.dispatch_loop_should_continue) {
    1120              18 :     dispatch_return = DISPATCH_CONTINUE;
    1121                 :   } else {
    1122               0 :     dispatch_return = DISPATCH_BREAK;
    1123                 :   }
    1124                 : 
    1125             122 :  done:
    1126             122 :   free(closure);
    1127             122 :   return dispatch_return;
    1128                 : }
    1129                 : 
    1130                 : /*
    1131                 :  * After an RPC is sent, the current thread can block waiting for the
    1132                 :  * response.  As currently there is only one thread receiving messages,
    1133                 :  * this thread will handle receiving and dispatching while waiting for
    1134                 :  * its response.  This allows for one thread to process calls back and
    1135                 :  * forth between client and server, as required for the NPAPI main thread
    1136                 :  * in Pepper.
    1137                 :  */
    1138                 : void NaClSrpcRpcWait(NaClSrpcChannel* channel,
    1139             122 :                      NaClSrpcRpc* rpc) {
    1140                 :   DispatchReturn retval;
    1141                 : 
    1142                 :   /*
    1143                 :    * Loop receiving RPCs and processing them.
    1144                 :    * The loop stops when the receive/dispatch function returns.
    1145                 :    */
    1146                 :   do {
    1147             122 :     retval = NaClSrpcReceiveAndDispatch(channel, rpc);
    1148             122 :   } while (DISPATCH_CONTINUE == retval);
    1149                 :   /* Process responses */
    1150             104 :   NaClSrpcLog(2,
    1151                 :               "NaClSrpcRpcWait(channel=%p): loop done: %p, %d\n",
    1152                 :               (void*) channel,
    1153                 :               (void*) rpc,
    1154                 :               retval);
    1155             104 :   if (NULL == rpc) {
    1156               7 :     NaClSrpcLog(2,
    1157                 :                 "NaClSrpcRpcWait(channel=%p):"
    1158                 :                 " rpc is NULL (this is not an error)\n",
    1159                 :                 (void*) channel);
    1160               7 :     return;
    1161                 :   }
    1162              97 :   if (DISPATCH_RESPONSE == retval) {
    1163              96 :     ssize_t recv_ret = RecvResponse(channel->message_channel, rpc, rpc->rets);
    1164              96 :     if (recv_ret < 0) {
    1165               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1166                 :                   "NaClSrpcRpcWait(channel=%p): rpc receive failed (%"
    1167                 :                   NACL_PRIdS")\n",
    1168                 :                   (void*) channel,
    1169                 :                   recv_ret);
    1170               0 :       rpc->result = NACL_SRPC_RESULT_INTERNAL;
    1171               0 :       return;
    1172                 :     }
    1173               1 :   } else if (DISPATCH_EOF == retval) {
    1174               1 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1175                 :                 "NaClSrpcRpcWait(channel=%p):"
    1176                 :                 " EOF is received instead of response. Probably, the other"
    1177                 :                 " side (usually, nacl module or browser plugin) crashed.\n",
    1178                 :                 (void*) channel);
    1179               1 :     rpc->result = NACL_SRPC_RESULT_INTERNAL;
    1180                 :   }
    1181                 : }
    1182                 : 
    1183                 : int NaClSrpcRequestWrite(NaClSrpcChannel* channel,
    1184                 :                          NaClSrpcRpc* rpc,
    1185                 :                          NaClSrpcArg** args,
    1186              97 :                          NaClSrpcArg** rets) {
    1187                 :   ssize_t retval;
    1188              97 :   rpc->is_request = 1;
    1189              97 :   retval = SrpcSendMessage(rpc, args, rets, channel->message_channel);
    1190              97 :   if (retval < 0) {
    1191                 :     /* Requests with bad handles could fail.  Report to the caller. */
    1192               0 :     NaClSrpcLog(1,
    1193                 :                 "NaClSrpcRequestWrite(channel=%p, retval=%"NACL_PRIu32
    1194                 :                 ") failed\n",
    1195                 :                 (void*) channel,
    1196                 :                 rpc->rpc_number);
    1197               0 :     return 0;
    1198                 :   }
    1199              97 :   return 1;
    1200                 : }

Generated by: LCOV version 1.7