LCOV - code coverage report
Current view: directory - src/shared/srpc - rpc_serialize.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 602 484 80.4 %
Date: 2014-06-18 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              19 : static ssize_t ErrnoFromImcRet(ssize_t imc_ret) {
     102              19 :   if (0 > imc_ret) {
     103              19 :     return imc_ret;
     104                 :   } else {
     105               0 :     return -NACL_ABI_EIO;
     106                 :   }
     107              19 : }
     108                 : 
     109            2114 : static void AddIovEntry(void* base,
     110            2114 :                         size_t length,
     111            2114 :                         size_t max_iov_len,
     112            2114 :                         struct NaClImcMsgIoVec* iov,
     113            2114 :                         size_t* iov_len,
     114            2114 :                         size_t* total_bytes) {
     115            2114 :   if (length == 0) {
     116               0 :     return;
     117                 :   }
     118            2114 :   if (*iov_len >= max_iov_len) {
     119               0 :     return;
     120                 :   }
     121            2114 :   iov[*iov_len].base = base;
     122            2114 :   iov[*iov_len].length = length;
     123            2114 :   ++*iov_len;
     124            2114 :   *total_bytes += length;
     125            4228 : }
     126                 : 
     127             576 : static nacl_abi_size_t VectorLen(NaClSrpcArg** vec) {
     128             576 :   nacl_abi_size_t len = 0;
     129            2396 :   for (len = 0; len <= NACL_SRPC_MAX_ARGS; ++len) {
     130            1198 :     if (vec[len] == NULL) {
     131             576 :       return len;
     132                 :     }
     133             622 :   }
     134               0 :   return NACL_SRPC_MAX_ARGS;
     135             576 : }
     136                 : 
     137             357 : static size_t ArrayElementSize(NaClSrpcArg* arg) {
     138             357 :   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             207 :       return 0;
     149                 : 
     150                 :     case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
     151             129 :       return sizeof *arg->arrays.carr;
     152                 :     case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
     153               2 :       return sizeof *arg->arrays.darr;
     154                 :     case NACL_SRPC_ARG_TYPE_INT_ARRAY:
     155               6 :       return sizeof *arg->arrays.iarr;
     156                 :     case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
     157               2 :       return sizeof *arg->arrays.larr;
     158                 :     case NACL_SRPC_ARG_TYPE_STRING:
     159              11 :       return sizeof *arg->arrays.str;
     160                 :   }
     161                 :   /* UNREACHED */
     162               0 :   return 0;
     163             357 : }
     164                 : 
     165              65 : static void ClearTemplateStringLengths(NaClSrpcArg** vec,
     166              65 :                                        size_t vec_len) {
     167              65 :   size_t i;
     168             274 :   for (i = 0; i < vec_len; ++i) {
     169              72 :     if (vec[i]->tag == NACL_SRPC_ARG_TYPE_STRING) {
     170               0 :       vec[i]->u.count = 0;
     171               0 :     }
     172              72 :   }
     173              65 : }
     174                 : 
     175                 : /*
     176                 :  * Adds the IOV entries for the fixed portion of the arguments in vec.
     177                 :  */
     178             836 : static void AddFixed(NaClSrpcArg** vec,
     179             836 :                      size_t vec_len,
     180             836 :                      size_t max_iov_len,
     181             836 :                      struct NaClImcMsgIoVec* iov,
     182             836 :                      size_t* iov_len,
     183             836 :                      size_t* expected_bytes) {
     184             836 :   size_t i;
     185            3308 :   for (i = 0; i < vec_len; ++i) {
     186             818 :     AddIovEntry(vec[i], kArgSize, max_iov_len, iov, iov_len, expected_bytes);
     187             818 :   }
     188             836 : }
     189                 : 
     190                 : /*
     191                 :  * Copies the handles/descriptors from descs into the appropriately typed
     192                 :  * elements of vec.
     193                 :  */
     194             234 : static BoolValue GetHandles(NaClSrpcArg** vec,
     195             234 :                             size_t vec_len,
     196             234 :                             NaClSrpcImcDescType* descs,
     197             234 :                             size_t desc_len) {
     198             234 :   size_t i;
     199             234 :   size_t handle_index = 0;
     200             936 :   for (i = 0; i < vec_len; ++i) {
     201             234 :     if (vec[i]->tag != NACL_SRPC_ARG_TYPE_HANDLE) {
     202             201 :       continue;
     203                 :     }
     204              33 :     if (handle_index >= desc_len) {
     205               0 :       return BoolFalse;
     206                 :     }
     207              33 :     vec[i]->u.hval = descs[handle_index];
     208              33 :     ++handle_index;
     209              33 :   }
     210             234 :   return BoolTrue;
     211             234 : }
     212                 : 
     213                 : /*
     214                 :  * Reads the header of the message to determine whether to call RecvRequest or
     215                 :  * RecvResponse.
     216                 :  */
     217             253 : static ssize_t SrpcPeekMessage(struct NaClSrpcMessageChannel* channel,
     218             253 :                                NaClSrpcRpc* rpc) {
     219             253 :   struct NaClImcMsgIoVec iov[1];
     220             253 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     221             253 :   size_t iov_len;
     222             253 :   NaClSrpcMessageHeader header;
     223             253 :   size_t expected_bytes;
     224             253 :   ssize_t retval;
     225                 : 
     226             253 :   iov_len = 0;
     227             253 :   expected_bytes = 0;
     228             253 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     229             253 :   header.iov = iov;
     230             253 :   header.iov_length = NACL_ARRAY_SIZE(iov);
     231             253 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
     232             253 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
     233             253 :   retval = NaClSrpcMessageChannelPeek(channel, &header);
     234                 :   /*
     235                 :    * Check that the peek read the RPC and that the argument lengths are sane.
     236                 :    */
     237             253 :   if (retval < (ssize_t) expected_bytes) {
     238              19 :     retval = ErrnoFromImcRet(retval);
     239              19 :   }
     240             468 :   else if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
     241                 :            rpc->template_len > NACL_SRPC_MAX_ARGS) {
     242               0 :     retval = -NACL_ABI_EIO;
     243               0 :   }
     244             253 :   return retval;
     245                 : }
     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             299 : static BoolValue AddNonfixedForRead(NaClSrpcArg** vec,
     258             299 :                                     size_t vec_len,
     259             299 :                                     size_t max_iov_len,
     260             299 :                                     BoolValue alloc_value,
     261             299 :                                     BoolValue read_value,
     262             299 :                                     struct NaClImcMsgIoVec* iov,
     263             299 :                                     size_t* iov_len,
     264             299 :                                     size_t* expected_bytes) {
     265             299 :   size_t i;
     266                 : 
     267                 :   /* Initialize the array pointers to allow cleanup if errors happen. */
     268             299 :   if (alloc_value) {
     269             456 :     for (i = 0; i < vec_len; ++i) {
     270              98 :       vec[i]->arrays.oval = NULL;
     271              98 :     }
     272             130 :   }
     273                 : 
     274            1210 :   for (i = 0; i < vec_len; ++i) {
     275             306 :     size_t count = vec[i]->u.count;
     276             306 :     void* base = 0;
     277             306 :     size_t element_size = ArrayElementSize(vec[i]);
     278                 : 
     279             306 :     if (element_size == 0) {
     280                 :       /* Skip fixed size arguments. */
     281             207 :       continue;
     282                 :     }
     283              99 :     if (SIZE_T_MAX / element_size < count) {
     284               0 :       return BoolFalse;
     285                 :     }
     286              99 :     base = vec[i]->arrays.oval;
     287              99 :     if (alloc_value) {
     288              36 :       base = malloc(element_size * count);
     289              36 :       if (base == 0) {
     290               0 :         return BoolFalse;
     291                 :       }
     292              36 :       vec[i]->arrays.oval = base;
     293              36 :     }
     294              99 :     if (read_value) {
     295              72 :       AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
     296                 :                   expected_bytes);
     297              72 :     }
     298              99 :   }
     299             299 :   return BoolTrue;
     300             299 : }
     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             819 : static void NaClSrpcArgVectorInit(NaClSrpcArg** arg_pointers) {
     308             819 :   arg_pointers[0] = NULL;
     309             819 : }
     310                 : 
     311             299 : static BoolValue AllocateArgs(NaClSrpcArg** arg_pointers, size_t length) {
     312             299 :   NaClSrpcArg* arg_array;
     313             299 :   nacl_abi_size_t i;
     314                 : 
     315                 :   /* Initialize the array pointers to allow cleanup if errors happen. */
     316            1808 :   for (i = 0; i < length + 1; ++i) {
     317             605 :     arg_pointers[i] = NULL;
     318             605 :   }
     319             299 :   if (length == 0) {
     320              80 :     return BoolTrue;
     321                 :   }
     322                 : 
     323             219 :   if (SIZE_T_MAX / sizeof **arg_pointers < length) {
     324               0 :     return BoolFalse;
     325                 :   }
     326             219 :   arg_array = (NaClSrpcArg*) malloc(length * sizeof **arg_pointers);
     327             219 :   if (arg_array == NULL) {
     328               0 :     return BoolFalse;
     329                 :   }
     330                 :   /* Initialize the individual args. */
     331            1050 :   for (i = 0; i < length; ++i) {
     332             306 :     NaClSrpcArgCtor(&arg_array[i]);
     333             306 :   }
     334                 :   /* Set each array pointer to point to the respective arg. */
     335            1050 :   for (i = 0; i < length; ++i) {
     336             306 :     arg_pointers[i] = &arg_array[i];
     337             306 :   }
     338             219 :   return BoolTrue;
     339             299 : }
     340                 : 
     341             425 : static void FreeArgs(NaClSrpcArg** vec) {
     342             425 :   nacl_abi_size_t i;
     343             425 :   NaClSrpcArg* args;
     344                 : 
     345             425 :   if (vec == NULL) {
     346             130 :     return;
     347                 :   }
     348             295 :   args = vec[0];
     349                 : 
     350            1202 :   for (i = 0; i <= NACL_SRPC_MAX_ARGS; ++i) {
     351             601 :     if (vec[i] == NULL) {
     352             295 :       break;
     353                 :     }
     354             612 :     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             207 :         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              99 :         free(vec[i]->arrays.oval);
     371              99 :         break;
     372                 :     }
     373             306 :     vec[i] = NULL;
     374             306 :   }
     375             295 :   free(args);
     376             720 : }
     377                 : 
     378              65 : static ssize_t RecvRequest(struct NaClSrpcMessageChannel* channel,
     379              65 :                            NaClSrpcRpc* rpc,
     380              65 :                            NaClSrpcArg** inputs,
     381              65 :                            NaClSrpcArg** results) {
     382              65 :   struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
     383              65 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     384              65 :   size_t iov_len;
     385              65 :   NaClSrpcMessageHeader header;
     386              65 :   NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
     387              65 :   size_t expected_bytes;
     388              65 :   ssize_t retval;
     389                 : 
     390              65 :   NaClSrpcArgVectorInit(results);
     391              65 :   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             195 :   if (!rpc->is_request ||
     398                 :       rpc->template_len > NACL_SRPC_MAX_ARGS ||
     399                 :       rpc->value_len > NACL_SRPC_MAX_ARGS) {
     400               0 :     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                 :                 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              65 :   if (!AllocateArgs(results, rpc->template_len) ||
     415              65 :       !AllocateArgs(inputs, rpc->value_len)) {
     416               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     417                 :                 "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              65 :   iov_len = 0;
     429              65 :   expected_bytes = 0;
     430              65 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     431              65 :   AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
     432                 :            &expected_bytes);
     433              65 :   AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     434              65 :   header.iov = iov;
     435              65 :   header.iov_length = (nacl_abi_size_t) iov_len;
     436              65 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
     437              65 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
     438              65 :   retval = NaClSrpcMessageChannelPeek(channel, &header);
     439              65 :   if (retval < (ssize_t) expected_bytes) {
     440               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     441                 :                 "RecvRequest:"
     442                 :                 "NaClSrpcMessageChannelPeek incomplete: expected %"
     443                 :                 NACL_PRIuS", got %"NACL_PRIdS"\n",
     444                 :                 expected_bytes,
     445                 :                 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              65 :   iov_len = 0;
     456              65 :   expected_bytes = 0;
     457              65 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     458              65 :   ClearTemplateStringLengths(results, rpc->template_len);
     459              65 :   AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
     460                 :            &expected_bytes);
     461              65 :   AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     462              65 :   if (!AddNonfixedForRead(results, rpc->template_len, kMaxIovLen,
     463                 :                           1, 0, iov, &iov_len, &expected_bytes)) {
     464               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     465                 :                 "RecvRequest: AllocateArgs failed for results\n");
     466               0 :     retval = -NACL_ABI_EIO;
     467               0 :     goto done;
     468                 :   }
     469              65 :   if (!AddNonfixedForRead(inputs, rpc->value_len, kMaxIovLen,
     470                 :                           1, 1, iov, &iov_len, &expected_bytes)) {
     471               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     472                 :                 "RecvRequest: AllocateArgs failed for inputs\n");
     473               0 :     retval = -NACL_ABI_EIO;
     474               0 :     goto done;
     475                 :   }
     476              65 :   header.iov = iov;
     477              65 :   header.iov_length = (nacl_abi_size_t) iov_len;
     478              65 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
     479              65 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
     480              65 :   retval = NaClSrpcMessageChannelReceive(channel, &header);
     481              65 :   if (retval < (ssize_t) expected_bytes) {
     482               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     483                 :                 "RecvRequest:"
     484                 :                 " NaClSrpcMessageChannelReceive incomplete: expected %"
     485                 :                 NACL_PRIuS", got %"NACL_PRIdS"\n",
     486                 :                 expected_bytes,
     487                 :                 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              65 :   if (!GetHandles(inputs, rpc->value_len,
     497                 :                   descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     498               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     499                 :                 "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              65 :   inputs = NULL;
     508              65 :   results = NULL;
     509                 : 
     510                 :  done:
     511              65 :   FreeArgs(inputs);
     512              65 :   FreeArgs(results);
     513              65 :   return retval;
     514                 : }
     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             169 : static BoolValue CheckMatchAndCopyCounts(size_t vec_len,
     524             169 :                                          NaClSrpcArg** expected,
     525             169 :                                          NaClSrpcArg** peeked) {
     526             169 :   size_t i;
     527                 : 
     528             754 :   for (i = 0; i < vec_len; ++i) {
     529             208 :     if (expected[i]->tag != peeked[i]->tag) {
     530               0 :       return BoolFalse;
     531                 :     }
     532             416 :     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             145 :         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               3 :           void *buffer = malloc(peeked[i]->u.count);
     552               3 :           if (buffer == NULL) {
     553               0 :             return BoolFalse;
     554                 :           }
     555               3 :           free(expected[i]->arrays.oval);
     556               3 :           expected[i]->arrays.oval = buffer;
     557               3 :           expected[i]->u.count = peeked[i]->u.count;
     558                 :         }
     559               3 :         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              60 :         if (peeked[i]->u.count > expected[i]->u.count) {
     566               0 :           return BoolFalse;
     567                 :         }
     568              60 :         expected[i]->u.count = peeked[i]->u.count;
     569              60 :         break;
     570                 :     }
     571             208 :   }
     572             169 :   return BoolTrue;
     573             169 : }
     574                 : 
     575             169 : static ssize_t RecvResponse(struct NaClSrpcMessageChannel* channel,
     576             169 :                             NaClSrpcRpc* rpc,
     577             169 :                             NaClSrpcArg** results) {
     578             169 :   NaClSrpcArg* result_copy[NACL_SRPC_MAX_ARGS + 1];
     579             169 :   struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
     580             169 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     581             169 :   size_t iov_len = 0;
     582             169 :   NaClSrpcMessageHeader header;
     583             169 :   NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
     584             169 :   size_t expected_bytes;
     585             169 :   ssize_t retval;
     586             169 :   size_t i;
     587                 : 
     588             169 :   NaClSrpcArgVectorInit(result_copy);
     589                 : 
     590             169 :   if (results == NULL) {
     591               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     592                 :                 "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             676 :   if (rpc->is_request ||
     601                 :       rpc->template_len > 0 ||
     602                 :       rpc->value_len > NACL_SRPC_MAX_ARGS ||
     603             169 :       rpc->value_len != VectorLen(results)) {
     604               0 :     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                 :                 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             169 :   if (!AllocateArgs(result_copy, rpc->value_len)) {
     623               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     624                 :                 "RecvResponse: AllocateArgs failed\n");
     625               0 :     retval = -NACL_ABI_EINVAL;
     626               0 :     goto done;
     627                 :   }
     628             169 :   iov_len = 0;
     629             169 :   expected_bytes = 0;
     630             169 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     631             754 :   for (i = 0; i < rpc->value_len; ++i) {
     632             208 :     AddIovEntry(result_copy[i], kArgSize, kMaxIovLen, iov, &iov_len,
     633                 :                 &expected_bytes);
     634             208 :   }
     635             169 :   header.iov = iov;
     636             169 :   header.iov_length = (nacl_abi_size_t) iov_len;
     637             169 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
     638             169 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
     639             169 :   retval = NaClSrpcMessageChannelPeek(channel, &header);
     640             169 :   if (retval < (ssize_t) expected_bytes) {
     641               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     642                 :                 "RecvResponse: NaClSrpcMessageChannelPeek incomplete: "
     643                 :                 "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
     644                 :                 expected_bytes,
     645                 :                 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             169 :   if (!CheckMatchAndCopyCounts(rpc->value_len, results, result_copy)) {
     657               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     658                 :                 "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             169 :   iov_len = 0;
     669             169 :   expected_bytes = 0;
     670             169 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     671             169 :   AddFixed(results, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     672             169 :   if (!AddNonfixedForRead(results, rpc->value_len, kMaxIovLen,
     673                 :                           0, 1, iov, &iov_len, &expected_bytes)) {
     674               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     675                 :                 "RecvResponse: AddNonfixedForRead failed\n");
     676               0 :     retval = -NACL_ABI_EIO;
     677               0 :     goto done;
     678                 :   }
     679             169 :   header.iov = iov;
     680             169 :   header.iov_length = (nacl_abi_size_t) iov_len;
     681             169 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
     682             169 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
     683             169 :   retval = NaClSrpcMessageChannelReceive(channel, &header);
     684             169 :   if (retval < (ssize_t) expected_bytes) {
     685               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     686                 :                 "RecvResponse: NaClSrpcMessageChannelReceive incomplete: "
     687                 :                 "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
     688                 :                 expected_bytes,
     689                 :                 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             169 :   if (!GetHandles(results, rpc->value_len,
     699                 :                   descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     700               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     701                 :                 "RecvResponse: GetHandles failed\n");
     702               0 :     retval = -NACL_ABI_EIO;
     703             169 :   }
     704                 : 
     705                 :  done:
     706             169 :   FreeArgs(result_copy);
     707             169 :   return retval;
     708                 : }
     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             235 : static BoolValue AddNonfixedForWrite(NaClSrpcArg** vec,
     715             235 :                                      size_t vec_len,
     716             235 :                                      size_t max_iov_len,
     717             235 :                                      struct NaClImcMsgIoVec* iov,
     718             235 :                                      size_t* iov_len,
     719             235 :                                      NaClSrpcImcDescType* descs,
     720             235 :                                      size_t* desc_len,
     721             235 :                                      size_t* expected_bytes) {
     722             235 :   size_t i;
     723             235 :   size_t element_size;
     724             235 :   nacl_abi_size_t count;
     725             235 :   void* base;
     726                 : 
     727                 :   /* Add IOV entries for the array/string types in vec. */
     728             880 :   for (i = 0; i < vec_len; ++i) {
     729             410 :     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             117 :        break;
     739                 : 
     740                 :       case NACL_SRPC_ARG_TYPE_HANDLE:
     741                 :         /* Handles are added into the desc array. */
     742              35 :         descs[*desc_len] = vec[i]->u.hval;
     743              35 :         ++*desc_len;
     744              35 :         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              51 :         count = vec[i]->u.count;
     751              51 :         base = vec[i]->arrays.oval;
     752              51 :         element_size = ArrayElementSize(vec[i]);
     753                 :         /* Check that computing the number of bytes will not overflow. */
     754              51 :         if (SIZE_T_MAX / element_size < count) {
     755               0 :           return BoolFalse;
     756                 :         }
     757              51 :         AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
     758                 :                     expected_bytes);
     759              51 :         break;
     760                 : 
     761                 :       case NACL_SRPC_ARG_TYPE_STRING:
     762               2 :         count = (nacl_abi_size_t) strlen(vec[i]->arrays.str) + 1;
     763               2 :         base = vec[i]->arrays.oval;
     764               2 :         vec[i]->u.count = count;
     765               2 :         AddIovEntry(base, count, max_iov_len, iov, iov_len, expected_bytes);
     766               2 :         break;
     767                 :     }
     768             205 :   }
     769             235 :   return BoolTrue;
     770             235 : }
     771                 : 
     772             235 : static ssize_t SrpcSendMessage(NaClSrpcRpc* rpc,
     773             235 :                                NaClSrpcArg** inputs,
     774             235 :                                NaClSrpcArg** results,
     775             235 :                                struct NaClSrpcMessageChannel* channel) {
     776             235 :   NaClSrpcArg** values;
     777             235 :   struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
     778             235 :   const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
     779             235 :   size_t iov_len;
     780             235 :   NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
     781             235 :   size_t desc_len = 0;
     782             235 :   NaClSrpcMessageHeader header;
     783             235 :   ssize_t retval;
     784             235 :   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             235 :   iov_len = 0;
     794             235 :   expected_bytes = 0;
     795             235 :   AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
     796                 : 
     797             235 :   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             172 :     if (results == NULL) {
     805               0 :       rpc->template_len = 0;
     806               0 :     } else {
     807             172 :       rpc->template_len = VectorLen(results);
     808             172 :       AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
     809                 :                &expected_bytes);
     810                 :     }
     811             172 :     values = inputs;
     812             172 :   } else {
     813                 :     /*
     814                 :      * For responses there are no templates, and the values that will be passed
     815                 :      * are from results.
     816                 :      */
     817              63 :     values = results;
     818              63 :     rpc->template_len = 0;
     819                 :   }
     820                 :   /*
     821                 :    * Pass the fixed and nonfixed portions.
     822                 :    */
     823             235 :   if (values == NULL) {
     824               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     825                 :                 "SrpcSendMessage: values should not be NULL\n");
     826               0 :     return -NACL_ABI_EINVAL;
     827                 :   }
     828             235 :   rpc->value_len = VectorLen(values);
     829             235 :   AddFixed(values, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
     830             235 :   if (!AddNonfixedForWrite(values, rpc->value_len,
     831                 :                            kMaxIovLen,
     832                 :                            iov, &iov_len,
     833                 :                            descs, &desc_len,
     834                 :                            &expected_bytes)) {
     835               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     836                 :                 "SrpcSendMessage: AddNonfixedForWrite failed\n");
     837               0 :     return -NACL_ABI_EIO;
     838                 :   }
     839             235 :   header.iov = iov;
     840             235 :   header.iov_length = (nacl_abi_size_t) iov_len;
     841             235 :   header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
     842             235 :   header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) desc_len;
     843             235 :   retval = NaClSrpcMessageChannelSend(channel, &header);
     844             470 :   if (retval >= 0  && retval < (ssize_t) expected_bytes) {
     845               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     846                 :                 "SrpcSendMessage: NaClSrpcMessageChannelSend incomplete: "
     847                 :                 "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
     848                 :                 expected_bytes,
     849                 :                 retval);
     850               0 :     return -NACL_ABI_EIO;
     851                 :   }
     852             235 :   return retval;
     853             235 : }
     854                 : 
     855                 : /* TODO(sehr): make this public when the client side uses RPC. */
     856             260 : static BoolValue NaClSrpcRpcCtor(NaClSrpcRpc* rpc, NaClSrpcChannel* channel) {
     857             260 :   rpc->channel = channel;
     858             260 :   rpc->result = NACL_SRPC_RESULT_INTERNAL;
     859             260 :   rpc->rets = NULL;
     860             260 :   return BoolTrue;
     861                 : }
     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              63 : static void RpcCheckingClosureRun(NaClSrpcClosure* self) {
     870              63 :   RpcCheckingClosure* vself = (RpcCheckingClosure*) self;
     871              63 :   NaClSrpcRpc* rpc = vself->rpc;
     872              63 :   ssize_t retval;
     873                 : 
     874              63 :   do {
     875              63 :     const char* rpc_name;
     876              63 :     const char* arg_types;
     877              63 :     const char* ret_types;
     878              63 :     int i;
     879              63 :     NaClSrpcServiceMethodNameAndTypes(rpc->channel->server,
     880                 :                                       rpc->rpc_number,
     881                 :                                       &rpc_name,
     882                 :                                       &arg_types,
     883                 :                                       &ret_types);
     884             126 :     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              63 :                 NaClSrpcErrorString(rpc->result));
     893             270 :     for (i = 0; rpc->rets[i] != NULL; i++ ) {
     894              72 :       char buffer[256];
     895              72 :       NaClSrpcFormatArg(2, rpc->rets[i], buffer, NACL_ARRAY_SIZE(buffer));
     896              72 :       NaClSrpcLog(2,
     897                 :                   "RpcCheckingClosureRun: response(channel=%p, rets[%d]=%s)\n",
     898                 :                   (void*) rpc->channel,
     899                 :                   i,
     900                 :                   buffer);
     901              72 :     }
     902              63 :   } while(0);
     903                 :   /* Send the RPC response to the caller. */
     904              63 :   rpc->is_request = 0;
     905              63 :   rpc->dispatch_loop_should_continue = 1;
     906              63 :   if (NACL_SRPC_RESULT_BREAK == rpc->result) {
     907               0 :     NaClSrpcLog(2,
     908                 :                 "RpcCheckingClosureRun: server requested break\n");
     909               0 :     rpc->result = NACL_SRPC_RESULT_OK;
     910               0 :     rpc->dispatch_loop_should_continue = 0;
     911               0 :   }
     912              63 :   retval = SrpcSendMessage(rpc, NULL, rpc->rets, rpc->channel->message_channel);
     913              63 :   if (retval < 0) {
     914                 :     /* If the response write failed, drop request and continue. */
     915               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     916                 :                 "RpcCheckingClosureRun: response write failed\n");
     917               0 :   }
     918              63 :   free(self);
     919              63 : }
     920                 : 
     921             260 : static BoolValue RpcCheckingClosureCtor(RpcCheckingClosure* self,
     922             260 :                                         NaClSrpcRpc* rpc) {
     923             260 :   self->base.Run = RpcCheckingClosureRun;
     924             260 :   self->rpc = rpc;
     925             260 :   self->rpc->dispatch_loop_should_continue = 1;
     926             260 :   return BoolTrue;
     927                 : }
     928                 : 
     929              65 : static BoolValue RequestVectorTypesConform(NaClSrpcChannel* channel,
     930              65 :                                            NaClSrpcRpc* rpc,
     931              65 :                                            NaClSrpcArg** args,
     932              65 :                                            NaClSrpcArg** rets) {
     933              65 :   const char* rpc_name;
     934              65 :   const char* arg_types;
     935              65 :   const char* ret_types;
     936              65 :   ssize_t retval;
     937              65 :   size_t i;
     938                 : 
     939             130 :   if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
     940                 :       rpc->template_len > NACL_SRPC_MAX_ARGS) {
     941               0 :     return BoolFalse;
     942                 :   }
     943                 :   /* Get service discovery's remembered types for args and rets */
     944              65 :   retval = NaClSrpcServiceMethodNameAndTypes(channel->server,
     945                 :                                              rpc->rpc_number,
     946                 :                                              &rpc_name,
     947                 :                                              &arg_types,
     948                 :                                              &ret_types);
     949              65 :   if (!retval) {
     950               0 :     return BoolFalse;
     951                 :   }
     952                 :   /* Check that lengths match. */
     953             130 :   if (rpc->value_len != strlen(arg_types) ||
     954              65 :       rpc->template_len != strlen(ret_types)) {
     955               0 :     return BoolFalse;
     956                 :   }
     957                 :   /* Check args for type conformance. */
     958             182 :   for (i = 0; i < rpc->value_len; ++i) {
     959              26 :     if (args[i] == NULL) {
     960               0 :       return BoolFalse;
     961                 :     }
     962              26 :     if (args[i]->tag != (unsigned char) arg_types[i]) {
     963               0 :       return BoolFalse;
     964                 :     }
     965              26 :   }
     966              65 :   if (args[rpc->value_len] != NULL) {
     967               0 :     return BoolFalse;
     968                 :   }
     969                 :   /* Check rets for type conformance. */
     970             274 :   for (i = 0; i < rpc->template_len; ++i) {
     971              72 :     if (rets[i] == NULL) {
     972               0 :       return BoolFalse;
     973                 :     }
     974              72 :     if (rets[i]->tag != (unsigned char) ret_types[i]) {
     975               0 :       return BoolFalse;
     976                 :     }
     977              72 :   }
     978              65 :   if (rets[rpc->template_len] != NULL) {
     979               0 :     return BoolFalse;
     980                 :   }
     981              65 :   return BoolTrue;
     982              65 : }
     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             260 : static DispatchReturn NaClSrpcReceiveAndDispatch(NaClSrpcChannel* channel,
     996             260 :                                                  NaClSrpcRpc* rpc_stack_top) {
     997             260 :   NaClSrpcRpc rpc;
     998             260 :   NaClSrpcArg* args[NACL_SRPC_MAX_ARGS + 1];
     999             260 :   NaClSrpcArg* rets[NACL_SRPC_MAX_ARGS + 1];
    1000             260 :   NaClSrpcMethod method;
    1001             260 :   ssize_t bytes_read;
    1002             260 :   RpcCheckingClosure* closure = NULL;
    1003                 :   /* DISPATCH_EOF is the closest we have to an error return. */
    1004             260 :   DispatchReturn dispatch_return = DISPATCH_EOF;
    1005                 : 
    1006             260 :   NaClSrpcArgVectorInit(args);
    1007             260 :   NaClSrpcArgVectorInit(rets);
    1008                 : 
    1009             260 :   closure = (RpcCheckingClosure*) malloc(sizeof *closure);
    1010             260 :   if (NULL == closure) {
    1011               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1012                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1013                 :                 "closure malloc failed\n",
    1014                 :                 (void*) channel);
    1015               0 :     dispatch_return = DISPATCH_EOF;
    1016               0 :     goto done;
    1017                 :   }
    1018             260 :   if (!NaClSrpcRpcCtor(&rpc, channel) ||
    1019             260 :       !RpcCheckingClosureCtor(closure, &rpc)) {
    1020               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1021                 :                 "NaClSrpcReceiveAndDispatch(channel=%p): constructor failed\n",
    1022                 :                 (void*) channel);
    1023               0 :     goto done;
    1024                 :   }
    1025             253 :   rpc.rets = rets;
    1026                 :   /* Read a message from the channel. */
    1027             253 :   bytes_read = SrpcPeekMessage(channel->message_channel, &rpc);
    1028             253 :   if (bytes_read < 0) {
    1029              19 :     goto done;
    1030                 :   }
    1031             234 :   if (rpc.is_request) {
    1032                 :     /* This is a new request. */
    1033              65 :     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               0 :         NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1041                 :                     "NaClSrpcReceiveAndDispatch(channel=%p):"
    1042                 :                     "out of order request\n",
    1043                 :                     (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              65 :   } else {
    1051                 :     /* This is a response to a pending request. */
    1052             169 :     if (NULL == rpc_stack_top) {
    1053               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1054                 :                   "NaClSrpcReceiveAndDispatch(channel=%p):"
    1055                 :                   "response, no pending request\n",
    1056                 :                   (void*) channel);
    1057                 :       /* There is no pending request. Abort. */
    1058               0 :       dispatch_return = DISPATCH_BREAK;
    1059               0 :       goto done;
    1060                 :     } else {
    1061             169 :       if (rpc.request_id == rpc_stack_top->request_id) {
    1062                 :         /* Copy the serialized portion of the Rpc and process as a response. */
    1063             507 :         memcpy(rpc_stack_top, &rpc, kRpcSize);
    1064             169 :         dispatch_return = DISPATCH_RESPONSE;
    1065             169 :         goto done;
    1066                 :       } else {
    1067                 :         /* Received an out-of-order response.  Abort. */
    1068               0 :         NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1069                 :                     "NaClSrpcReceiveAndDispatch(channel=%p):"
    1070                 :                     " response for wrong request\n",
    1071                 :                     (void*) channel);
    1072               0 :         dispatch_return = DISPATCH_BREAK;
    1073               0 :         goto done;
    1074                 :       }
    1075                 :     }
    1076                 :   }
    1077              65 :   bytes_read = RecvRequest(channel->message_channel, &rpc, args, rets);
    1078              65 :   if (bytes_read < 0) {
    1079               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1080                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1081                 :                 "RecvRequest failed, bytes=%"NACL_PRIdS"\n",
    1082                 :                 (void*) channel,
    1083                 :                 bytes_read);
    1084               0 :     dispatch_return = DISPATCH_EOF;
    1085               0 :   }
    1086              65 :   if (!RequestVectorTypesConform(channel, &rpc, args, rets)) {
    1087               0 :     NaClSrpcLog(NACL_SRPC_LOG_WARNING,
    1088                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1089                 :                 " arg/ret type mismatch (recoverable error)\n",
    1090                 :                 (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              65 :   method = NaClSrpcServiceMethod(channel->server, rpc.rpc_number);
    1096              65 :   if (NULL == method) {
    1097               0 :     NaClSrpcLog(NACL_SRPC_LOG_WARNING,
    1098                 :                 "NaClSrpcReceiveAndDispatch(channel=%p):"
    1099                 :                 " bad rpc_number %"NACL_PRIu32" (recoverable error)\n",
    1100                 :                 (void*) channel,
    1101                 :                 rpc.rpc_number);
    1102               0 :     dispatch_return = DISPATCH_CONTINUE;
    1103               0 :     goto done;
    1104                 :   }
    1105              65 :   do {
    1106              65 :     const char* rpc_name;
    1107              65 :     const char* arg_types;
    1108              65 :     const char* ret_types;
    1109              65 :     int i;
    1110              65 :     NaClSrpcServiceMethodNameAndTypes(channel->server,
    1111                 :                                       rpc.rpc_number,
    1112                 :                                       &rpc_name,
    1113                 :                                       &arg_types,
    1114                 :                                       &ret_types);
    1115              65 :     NaClSrpcLog(1, "NaClSrpcReceiveAndDispatch:"
    1116                 :                 " request(channel=%p, rpc_number=%"NACL_PRIu32
    1117                 :                 ", rpc_name=\"%s\")\n",
    1118                 :                 (void*) channel,
    1119                 :                 rpc.rpc_number,
    1120                 :                 rpc_name);
    1121             182 :     for (i = 0; args[i] != NULL; i++ ) {
    1122              26 :       char buffer[256];
    1123              26 :       NaClSrpcFormatArg(2, args[i], buffer, NACL_ARRAY_SIZE(buffer));
    1124              26 :       NaClSrpcLog(2,
    1125                 :                   "NaClSrpcReceiveAndDispatch:"
    1126                 :                   " request(channel=%p, args[%d]=%s)\n",
    1127                 :                   (void*) channel,
    1128                 :                   i,
    1129                 :                   buffer);
    1130              26 :     }
    1131              65 :   } while(0);
    1132              63 :   (*method)(&rpc, args, rets, (NaClSrpcClosure*) closure);
    1133              63 :   FreeArgs(args);
    1134              63 :   FreeArgs(rets);
    1135                 :   /* The invoked method takes ownership of the closure and deletes it. */
    1136              63 :   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              63 :   if (rpc.dispatch_loop_should_continue) {
    1144              63 :     dispatch_return = DISPATCH_CONTINUE;
    1145              63 :   } else {
    1146               0 :     dispatch_return = DISPATCH_BREAK;
    1147              63 :   }
    1148                 : 
    1149                 :  done:
    1150             251 :   free(closure);
    1151             251 :   return dispatch_return;
    1152                 : }
    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             197 : void NaClSrpcRpcWait(NaClSrpcChannel* channel,
    1163             197 :                      NaClSrpcRpc* rpc) {
    1164             197 :   DispatchReturn retval;
    1165                 : 
    1166                 :   /*
    1167                 :    * Loop receiving RPCs and processing them.
    1168                 :    * The loop stops when the receive/dispatch function returns.
    1169                 :    */
    1170             197 :   do {
    1171             260 :     retval = NaClSrpcReceiveAndDispatch(channel, rpc);
    1172             511 :   } while (DISPATCH_CONTINUE == retval);
    1173                 :   /* Process responses */
    1174             188 :   NaClSrpcLog(2,
    1175                 :               "NaClSrpcRpcWait(channel=%p): loop done: %p, %d\n",
    1176                 :               (void*) channel,
    1177                 :               (void*) rpc,
    1178                 :               retval);
    1179             188 :   if (NULL == rpc) {
    1180              16 :     NaClSrpcLog(2,
    1181                 :                 "NaClSrpcRpcWait(channel=%p):"
    1182                 :                 " rpc is NULL (this is not an error)\n",
    1183                 :                 (void*) channel);
    1184              16 :     return;
    1185                 :   }
    1186             172 :   if (DISPATCH_RESPONSE == retval) {
    1187             169 :     ssize_t recv_ret = RecvResponse(channel->message_channel, rpc, rpc->rets);
    1188             169 :     if (recv_ret < 0) {
    1189               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1190                 :                   "NaClSrpcRpcWait(channel=%p): rpc receive failed (%"
    1191                 :                   NACL_PRIdS")\n",
    1192                 :                   (void*) channel,
    1193                 :                   recv_ret);
    1194               0 :       rpc->result = NACL_SRPC_RESULT_INTERNAL;
    1195               0 :       return;
    1196                 :     }
    1197             172 :   } else if (DISPATCH_EOF == retval) {
    1198               3 :     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                 :                 (void*) channel);
    1203               3 :     rpc->result = NACL_SRPC_RESULT_INTERNAL;
    1204               3 :   }
    1205             188 : }
    1206                 : 
    1207             172 : int NaClSrpcRequestWrite(NaClSrpcChannel* channel,
    1208             172 :                          NaClSrpcRpc* rpc,
    1209             172 :                          NaClSrpcArg** args,
    1210             172 :                          NaClSrpcArg** rets) {
    1211             172 :   ssize_t retval;
    1212             172 :   rpc->is_request = 1;
    1213             172 :   retval = SrpcSendMessage(rpc, args, rets, channel->message_channel);
    1214             172 :   if (retval < 0) {
    1215                 :     /* Requests with bad handles could fail.  Report to the caller. */
    1216               0 :     NaClSrpcLog(1,
    1217                 :                 "NaClSrpcRequestWrite(channel=%p, retval=%"NACL_PRIu32
    1218                 :                 ") failed\n",
    1219                 :                 (void*) channel,
    1220                 :                 rpc->rpc_number);
    1221               0 :     return 0;
    1222                 :   }
    1223             172 :   return 1;
    1224             172 : }

Generated by: LCOV version 1.7