LCOV - code coverage report
Current view: directory - src/trusted/desc/posix - nacl_desc_conn_cap.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 98 75 76.5 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl Service Runtime.  I/O Descriptor / Handle abstraction.
       9                 :  * Connection capabilities.
      10                 :  */
      11                 : 
      12                 : #include <assert.h>
      13                 : #include <errno.h>
      14                 : #include <poll.h>
      15                 : #include <stdlib.h>
      16                 : #include <string.h>
      17                 : #include <sys/socket.h>
      18                 : 
      19                 : #include "native_client/src/include/nacl_macros.h"
      20                 : #include "native_client/src/include/portability.h"
      21                 : 
      22                 : #include "native_client/src/shared/imc/nacl_imc_c.h"
      23                 : #include "native_client/src/shared/platform/nacl_check.h"
      24                 : #include "native_client/src/shared/platform/nacl_log.h"
      25                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      26                 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
      27                 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
      28                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      29                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      30                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      31                 : 
      32                 : static struct NaClDescVtbl const kNaClDescConnCapFdVtbl;  /* fwd */
      33                 : 
      34                 : int NaClDescConnCapFdCtor(struct NaClDescConnCapFd  *self,
      35              36 :                           NaClHandle                endpt) {
      36              36 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      37                 : 
      38              36 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
      39              36 :   if (!NaClDescCtor(basep)) {
      40               0 :     return 0;
      41                 :   }
      42              36 :   self->connect_fd = endpt;
      43              36 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescConnCapFdVtbl;
      44              36 :   return 1;
      45                 : }
      46                 : 
      47                 : 
      48              31 : static void NaClDescConnCapFdDtor(struct NaClRefCount *vself) {
      49              31 :   struct NaClDescConnCapFd *self = (struct NaClDescConnCapFd *) vself;
      50                 : 
      51              31 :   (void) NaClClose(self->connect_fd);
      52              31 :   self->connect_fd = NACL_INVALID_HANDLE;
      53              31 :   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
      54              31 :   (*vself->vtbl->Dtor)(vself);
      55                 :   return;
      56                 : }
      57                 : 
      58                 : static int NaClDescConnCapFdFstat(struct NaClDesc       *vself,
      59               0 :                                   struct nacl_abi_stat  *statbuf) {
      60                 :   UNREFERENCED_PARAMETER(vself);
      61                 : 
      62               0 :   memset(statbuf, 0, sizeof *statbuf);
      63               0 :   statbuf->nacl_abi_st_mode = NACL_ABI_S_IFSOCKADDR | NACL_ABI_S_IRWXU;
      64               0 :   return 0;
      65                 : }
      66                 : 
      67                 : static int NaClDescConnCapFdExternalizeSize(struct NaClDesc *vself,
      68                 :                                             size_t          *nbytes,
      69               9 :                                             size_t          *nhandles) {
      70                 :   UNREFERENCED_PARAMETER(vself);
      71                 : 
      72               9 :   *nbytes = 0;
      73               9 :   *nhandles = 1;
      74                 : 
      75               9 :   return 0;
      76                 : }
      77                 : 
      78                 : static int NaClDescConnCapFdExternalize(struct NaClDesc          *vself,
      79               9 :                                         struct NaClDescXferState *xfer) {
      80                 :   struct NaClDescConnCapFd    *self;
      81                 : 
      82               9 :   self = (struct NaClDescConnCapFd *) vself;
      83               9 :   *xfer->next_handle++ = self->connect_fd;
      84                 : 
      85               9 :   return 0;
      86                 : }
      87                 : 
      88                 : static int NaClDescConnCapFdConnectAddr(struct NaClDesc *vself,
      89              46 :                                         struct NaClDesc **out_desc) {
      90              46 :   struct NaClDescConnCapFd  *self = (struct NaClDescConnCapFd *) vself;
      91                 :   NaClHandle                sock_pair[2];
      92                 :   struct NaClDescImcDesc    *connected_socket;
      93                 :   char                      control_buf[CMSG_SPACE_KHANDLE_COUNT_MAX_INTS];
      94                 :   struct iovec              iovec;
      95                 :   struct msghdr             connect_msg;
      96                 :   struct cmsghdr            *cmsg;
      97                 :   int                       sent;
      98                 :   int                       retval;
      99                 : 
     100                 :   assert(CMSG_SPACE(sizeof(int)) <= CMSG_SPACE_KHANDLE_COUNT_MAX_INTS);
     101                 : 
     102              46 :   sock_pair[0] = NACL_INVALID_HANDLE;
     103              46 :   sock_pair[1] = NACL_INVALID_HANDLE;
     104              46 :   connected_socket = (struct NaClDescImcDesc *) NULL;
     105                 : 
     106              46 :   retval = -NACL_ABI_EINVAL;
     107                 : 
     108              46 :   if (0 != NaClSocketPair(sock_pair)) {
     109               0 :     retval = -NACL_ABI_EMFILE;
     110               0 :     goto cleanup;
     111                 :   }
     112                 : 
     113              46 :   iovec.iov_base = "c";
     114              46 :   iovec.iov_len = 1;
     115              46 :   connect_msg.msg_iov = &iovec;
     116              46 :   connect_msg.msg_iovlen = 1;
     117              46 :   connect_msg.msg_name = NULL;
     118              46 :   connect_msg.msg_namelen = 0;
     119              46 :   connect_msg.msg_control = control_buf;
     120              46 :   connect_msg.msg_controllen = sizeof(control_buf);
     121              46 :   connect_msg.msg_flags = 0;
     122                 : 
     123              46 :   cmsg = CMSG_FIRSTHDR(&connect_msg);
     124              46 :   cmsg->cmsg_len = CMSG_LEN(sizeof(int));
     125              46 :   cmsg->cmsg_level = SOL_SOCKET;
     126              46 :   cmsg->cmsg_type = SCM_RIGHTS;
     127                 :   /*
     128                 :    * We use memcpy() rather than assignment through a cast to avoid
     129                 :    * strict-aliasing warnings
     130                 :    */
     131              46 :   memcpy(CMSG_DATA(cmsg), &sock_pair[0], sizeof(int));
     132                 :   /* Set msg_controllen to the actual size of the cmsg. */
     133              46 :   connect_msg.msg_controllen = cmsg->cmsg_len;
     134                 : 
     135              46 :   sent = sendmsg(self->connect_fd, &connect_msg, 0);
     136              46 :   if (1 != sent) {
     137               0 :     retval = -NACL_ABI_EIO;
     138               0 :     goto cleanup;
     139                 :   }
     140                 : 
     141                 :   if (NACL_OSX) {
     142                 :     /*
     143                 :      * Mac OS X has a kernel bug in which a socket descriptor that is
     144                 :      * referenced only from the message queue of another socket can
     145                 :      * get garbage collected.  This causes the socket descriptor not
     146                 :      * to work properly.  To work around this, we don't close our
     147                 :      * reference to the socket until we receive an acknowledgement
     148                 :      * that it has been successfully received.
     149                 :      *
     150                 :      * We cannot receive the acknowledgement through self->connect_fd
     151                 :      * because this FD could be shared between multiple processes.  So
     152                 :      * we receive the acknowledgement through the socket pair that we
     153                 :      * have just created.
     154                 :      *
     155                 :      * However, this creates a risk that we are left hanging if the
     156                 :      * other process dies after our sendmsg() call, because we are
     157                 :      * holding on to the socket that it would use to send the ack.  To
     158                 :      * avoid this problem, we use poll() so that we will be notified
     159                 :      * if self->connect_fd becomes unwritable.
     160                 :      * TODO(mseaborn): Add a test case to simulate that scenario.
     161                 :      *
     162                 :      * See http://code.google.com/p/nativeclient/issues/detail?id=1796
     163                 :      *
     164                 :      * Note that we are relying on a corner case of poll() here.
     165                 :      * Using POLLHUP in "events" is not meaningful on Linux, which is
     166                 :      * documented as ignoring POLLHUP as an input argument and will
     167                 :      * return POLLHUP in "revents" even if it not present in "events".
     168                 :      * On Mac OS X, however, passing events == 0 does not work if we
     169                 :      * want to get POLLHUP.  We are in the unusual situation of
     170                 :      * waiting for a socket to become *un*writable.
     171                 :      */
     172                 :     struct pollfd poll_fds[2];
     173              46 :     poll_fds[0].fd = self->connect_fd;
     174              46 :     poll_fds[0].events = POLLHUP;
     175              46 :     poll_fds[1].fd = sock_pair[1];
     176              46 :     poll_fds[1].events = POLLIN;
     177              46 :     if (poll(poll_fds, 2, -1) < 0) {
     178               0 :       NaClLog(LOG_ERROR,
     179                 :               "NaClDescConnCapFdConnectAddr: poll() failed, errno %d\n", errno);
     180               0 :       retval = -NACL_ABI_EIO;
     181               0 :       goto cleanup;
     182                 :     }
     183                 :     /*
     184                 :      * It is not necessarily an error if POLLHUP fires on
     185                 :      * self->connect_fd: The other process could have done
     186                 :      * imc_accept(S) and then closed S.  This means it will have
     187                 :      * received sock_pair[0] successfully, so we can close our
     188                 :      * reference to sock_pair[0] and then receive the ack.
     189                 :      * TODO(mseaborn): Add a test case to cover this scenario.
     190                 :      */
     191                 :   }
     192                 : 
     193              46 :   (void) NaClClose(sock_pair[0]);
     194              46 :   sock_pair[0] = NACL_INVALID_HANDLE;
     195                 : 
     196                 :   if (NACL_OSX) {
     197                 :     /* Receive the acknowledgement.  We do not expect this to block. */
     198                 :     char ack_buffer[1];
     199              46 :     ssize_t received = recv(sock_pair[1], ack_buffer, sizeof(ack_buffer), 0);
     200              46 :     if (received != 1 || ack_buffer[0] != 'a') {
     201               0 :       retval = -NACL_ABI_EIO;
     202               0 :       goto cleanup;
     203                 :     }
     204                 :   }
     205                 : 
     206              46 :   connected_socket = malloc(sizeof(*connected_socket));
     207              46 :   if (NULL == connected_socket ||
     208                 :       !NaClDescImcDescCtor(connected_socket, sock_pair[1])) {
     209               0 :     retval = -NACL_ABI_ENOMEM;
     210               0 :     goto cleanup;
     211                 :   }
     212              46 :   sock_pair[1] = NACL_INVALID_HANDLE;
     213                 : 
     214              46 :   *out_desc = (struct NaClDesc *) connected_socket;
     215              46 :   connected_socket = NULL;
     216              46 :   retval = 0;
     217                 : 
     218              46 : cleanup:
     219              46 :   NaClSafeCloseNaClHandle(sock_pair[0]);
     220              46 :   NaClSafeCloseNaClHandle(sock_pair[1]);
     221              46 :   free(connected_socket);
     222                 : 
     223              46 :   return retval;
     224                 : }
     225                 : 
     226                 : static int NaClDescConnCapFdAcceptConn(struct NaClDesc  *vself,
     227               0 :                                        struct NaClDesc  **out_desc) {
     228                 :   UNREFERENCED_PARAMETER(vself);
     229                 :   UNREFERENCED_PARAMETER(out_desc);
     230                 : 
     231               0 :   NaClLog(LOG_ERROR, "NaClDescConnCapFdAcceptConn: not IMC\n");
     232               0 :   return -NACL_ABI_EINVAL;
     233                 : }
     234                 : 
     235                 : static struct NaClDescVtbl const kNaClDescConnCapFdVtbl = {
     236                 :   {
     237                 :     NaClDescConnCapFdDtor,
     238                 :   },
     239                 :   NaClDescMapNotImplemented,
     240                 :   NaClDescUnmapUnsafeNotImplemented,
     241                 :   NaClDescUnmapNotImplemented,
     242                 :   NaClDescReadNotImplemented,
     243                 :   NaClDescWriteNotImplemented,
     244                 :   NaClDescSeekNotImplemented,
     245                 :   NaClDescIoctlNotImplemented,
     246                 :   NaClDescConnCapFdFstat,
     247                 :   NaClDescGetdentsNotImplemented,
     248                 :   NACL_DESC_CONN_CAP_FD,
     249                 :   NaClDescConnCapFdExternalizeSize,
     250                 :   NaClDescConnCapFdExternalize,
     251                 :   NaClDescLockNotImplemented,
     252                 :   NaClDescTryLockNotImplemented,
     253                 :   NaClDescUnlockNotImplemented,
     254                 :   NaClDescWaitNotImplemented,
     255                 :   NaClDescTimedWaitAbsNotImplemented,
     256                 :   NaClDescSignalNotImplemented,
     257                 :   NaClDescBroadcastNotImplemented,
     258                 :   NaClDescSendMsgNotImplemented,
     259                 :   NaClDescRecvMsgNotImplemented,
     260                 :   NaClDescConnCapFdConnectAddr,
     261                 :   NaClDescConnCapFdAcceptConn,
     262                 :   NaClDescPostNotImplemented,
     263                 :   NaClDescSemWaitNotImplemented,
     264                 :   NaClDescGetValueNotImplemented,
     265                 : };
     266                 : 
     267                 : int NaClDescConnCapFdInternalize(
     268                 :     struct NaClDesc               **out_desc,
     269                 :     struct NaClDescXferState      *xfer,
     270              23 :     struct NaClDescQuotaInterface *quota_interface) {
     271                 :   struct NaClDescConnCapFd *conn_cap;
     272                 : 
     273                 :   UNREFERENCED_PARAMETER(quota_interface);
     274              23 :   if (xfer->next_handle == xfer->handle_buffer_end) {
     275               0 :     return -NACL_ABI_EIO;
     276                 :   }
     277              23 :   conn_cap = malloc(sizeof(*conn_cap));
     278              23 :   if (NULL == conn_cap) {
     279               0 :     return -NACL_ABI_ENOMEM;
     280                 :   }
     281              23 :   if (!NaClDescCtor(&conn_cap->base)) {
     282               0 :     free(conn_cap);
     283               0 :     return -NACL_ABI_ENOMEM;
     284                 :   }
     285              23 :   conn_cap->base.base.vtbl =
     286                 :       (struct NaClRefCountVtbl const *) &kNaClDescConnCapFdVtbl;
     287              23 :   conn_cap->connect_fd = *xfer->next_handle;
     288              23 :   *xfer->next_handle++ = NACL_INVALID_HANDLE;
     289              23 :   *out_desc = &conn_cap->base;
     290              23 :   return 0;
     291                 : }

Generated by: LCOV version 1.7