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

Generated by: LCOV version 1.7