LCOV - code coverage report
Current view: directory - src/shared/imc/win - nacl_imc.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 287 161 56.1 %
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 inter-module communication primitives. */
       9                 : 
      10                 : /* Disables the generation of the min and max macro in <windows.h> */
      11                 : #ifndef NOMINMAX
      12                 : #define NOMINMAX
      13                 : #endif
      14                 : 
      15                 : #include <algorithm>
      16                 : #include <ctype.h>
      17                 : #include <limits.h>
      18                 : #include <stdio.h>
      19                 : #include <string>
      20                 : #include <windows.h>
      21                 : #include <sys/types.h>
      22                 : 
      23                 : #include "native_client/src/include/atomic_ops.h"
      24                 : #include "native_client/src/include/portability.h"
      25                 : #include "native_client/src/shared/imc/nacl_imc_c.h"
      26                 : 
      27                 : 
      28                 : static NaClBrokerDuplicateHandleFunc g_broker_duplicate_handle_func;
      29                 : 
      30               0 : void NaClSetBrokerDuplicateHandleFunc(NaClBrokerDuplicateHandleFunc func) {
      31               0 :   g_broker_duplicate_handle_func = func;
      32               0 : }
      33                 : 
      34                 : /* Duplicate a Windows HANDLE within the current process. */
      35               0 : NaClHandle NaClDuplicateNaClHandle(NaClHandle handle) {
      36                 :   NaClHandle dup_handle;
      37                 :   if (DuplicateHandle(GetCurrentProcess(),
      38                 :                       handle,
      39                 :                       GetCurrentProcess(),
      40                 :                       &dup_handle,
      41                 :                       0,
      42                 :                       FALSE,
      43               0 :                       DUPLICATE_SAME_ACCESS)) {
      44               0 :     return dup_handle;
      45                 :   } else {
      46               0 :     return NACL_INVALID_HANDLE;
      47                 :   }
      48               0 : }
      49                 : 
      50                 : /*
      51                 :  * This prefix used to be appended to pipe names for pipes
      52                 :  * created in BoundSocket. We keep it for backward compatibility.
      53                 :  * TODO(gregoryd): implement versioning support
      54                 :  */
      55                 : static const char kOldPipePrefix[] = "\\\\.\\pipe\\google-nacl-";
      56                 : static const char kPipePrefix[] = "\\\\.\\pipe\\chrome.nacl.";
      57                 : 
      58                 : static const size_t kPipePrefixSize =
      59                 :     sizeof kPipePrefix / sizeof kPipePrefix[0];
      60                 : static const size_t kOldPipePrefixSize =
      61                 :     sizeof kOldPipePrefix / sizeof kOldPipePrefix[0];
      62                 : 
      63                 : static const int kPipePathMax = kPipePrefixSize + NACL_PATH_MAX + 1;
      64                 : static const int kOutBufferSize = 4096;  /* TBD */
      65                 : static const int kInBufferSize = 4096;   /* TBD */
      66                 : static const int kDefaultTimeoutMilliSeconds = 1000;
      67                 : 
      68                 : /* ControlHeader::command */
      69                 : static const int kEchoRequest = 0;
      70                 : static const int kEchoResponse = 1;
      71                 : static const int kMessage = 2;
      72                 : static const int kCancel = 3;   /* Cancels Handle transfer operations */
      73                 : 
      74                 : struct ControlHeader {
      75                 :   int command;
      76                 :   DWORD pid;
      77                 :   uint32_t message_length;
      78                 :   uint32_t handle_count;
      79                 : };
      80                 : 
      81                 : /*
      82                 :  * TODO(gregoryd): a similar function exists in Chrome's base, but we cannot
      83                 :  * use it here since it cannot be built with scons.
      84                 :  */
      85               7 : static std::wstring ASCIIToWide(const char* ascii) {
      86               7 :   return std::wstring(ascii, &ascii[strlen(ascii)]);
      87               7 : }
      88                 : 
      89               3 : static bool GetSocketName(const NaClSocketAddress* address, char* name) {
      90               3 :   if (address == NULL || !isprint(address->path[0])) {
      91               0 :     SetLastError(ERROR_INVALID_PARAMETER);
      92               0 :     return false;
      93                 :   }
      94                 :   sprintf_s(name, kPipePathMax, "%s%.*s",
      95               3 :     kPipePrefix, NACL_PATH_MAX, address->path);
      96               3 :   return true;
      97               3 : }
      98                 : 
      99                 : static bool GetSocketNameWithOldPrefix(const NaClSocketAddress* address,
     100               1 :                                        char* name) {
     101               1 :   if (address == NULL || !isprint(address->path[0])) {
     102               0 :     SetLastError(ERROR_INVALID_PARAMETER);
     103               0 :     return false;
     104                 :   }
     105                 :   sprintf_s(name, kPipePathMax, "%s%.*s",
     106               1 :             kOldPipePrefix, NACL_PATH_MAX, address->path);
     107               1 :   return true;
     108               1 : }
     109                 : 
     110               5 : static int ReadAll(HANDLE handle, void* buffer, size_t length) {
     111               5 :   size_t count = 0;
     112               5 :   while (count < length) {
     113                 :     DWORD len;
     114                 :     DWORD chunk = (DWORD) (
     115               5 :       ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
     116                 :     if (ReadFile(handle, (char *) buffer + count,
     117               5 :                  chunk, &len, NULL) == FALSE) {
     118               2 :       return (int) ((0 < count) ? count : -1);
     119                 :     }
     120               5 :     count += len;
     121               5 :   }
     122               5 :   return (int) count;
     123               5 : }
     124                 : 
     125               5 : static int WriteAll(HANDLE handle, const void* buffer, size_t length) {
     126               5 :   size_t count = 0;
     127               5 :   while (count < length) {
     128                 :     DWORD len;
     129                 :     /* The following statement is for the 64 bit portability. */
     130                 :     DWORD chunk = (DWORD) (
     131               5 :       ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
     132                 :     if (WriteFile(handle, (const char *) buffer + count,
     133               5 :                   chunk, &len, NULL) == FALSE) {
     134               1 :       return (int) ((0 < count) ? count : -1);
     135                 :     }
     136               5 :     count += len;
     137               5 :   }
     138               5 :   return (int) count;
     139               5 : }
     140                 : 
     141               0 : static BOOL SkipFile(HANDLE handle, size_t length) {
     142               0 :   while (0 < length) {
     143                 :     char scratch[1024];
     144               0 :     size_t count = std::min(sizeof scratch, length);
     145               0 :     if (ReadAll(handle, scratch, count) != count) {
     146               0 :       return FALSE;
     147                 :     }
     148               0 :     length -= count;
     149               0 :   }
     150               0 :   return TRUE;
     151               0 : }
     152                 : 
     153               0 : static BOOL SkipHandles(HANDLE handle, size_t count) {
     154               0 :   while (0 < count) {
     155                 :     uint64_t discard;
     156               0 :     if (ReadAll(handle, &discard, sizeof discard) != sizeof discard) {
     157               0 :       return FALSE;
     158                 :     }
     159               0 :     CloseHandle((HANDLE) discard);
     160               0 :     --count;
     161               0 :   }
     162               0 :   return TRUE;
     163               0 : }
     164                 : 
     165               0 : int NaClWouldBlock() {
     166               0 :   return GetLastError() == ERROR_PIPE_LISTENING;
     167               0 : }
     168                 : 
     169               3 : NaClHandle NaClBoundSocket(const NaClSocketAddress* address) {
     170                 :   char name[kPipePathMax];
     171               3 :   if (!GetSocketName(address, name)) {
     172               0 :     return NACL_INVALID_HANDLE;
     173                 :   }
     174                 :   /* Create a named pipe in nonblocking mode. */
     175                 :   return CreateNamedPipeW(
     176                 :       ASCIIToWide(name).c_str(),
     177                 :       PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
     178                 :       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT,
     179                 :       PIPE_UNLIMITED_INSTANCES,
     180                 :       kOutBufferSize,
     181                 :       kInBufferSize,
     182                 :       kDefaultTimeoutMilliSeconds,
     183               3 :       NULL);
     184               3 : }
     185                 : 
     186               7 : int NaClSocketPair(NaClHandle pair[2]) {
     187                 :   static Atomic32 socket_pair_count;
     188                 :   char name[kPipePathMax];
     189                 : 
     190                 :   do {
     191                 :     sprintf_s(name, kPipePathMax, "%s%u.%lu",
     192                 :               kPipePrefix, GetCurrentProcessId(),
     193               7 :               AtomicIncrement(&socket_pair_count, 1));
     194                 :     pair[0] = CreateNamedPipeW(
     195                 :         ASCIIToWide(name).c_str(),
     196                 :         PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
     197                 :         PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
     198                 :         1,
     199                 :         kOutBufferSize,
     200                 :         kInBufferSize,
     201                 :         kDefaultTimeoutMilliSeconds,
     202               7 :         NULL);
     203                 :     if (pair[0] == INVALID_HANDLE_VALUE &&
     204                 :         GetLastError() != ERROR_ACCESS_DENIED &&
     205               7 :         GetLastError() != ERROR_PIPE_BUSY) {
     206               0 :       return -1;
     207                 :     }
     208               7 :   } while (pair[0] == INVALID_HANDLE_VALUE);
     209                 :   pair[1] = CreateFileW(ASCIIToWide(name).c_str(),
     210                 :                         GENERIC_READ | GENERIC_WRITE,
     211                 :                         0,              /* no sharing */
     212                 :                         NULL,           /* default security attributes */
     213                 :                         OPEN_EXISTING,  /* opens existing pipe */
     214                 :                         SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
     215               7 :                         NULL);          /* no template file */
     216               7 :   if (pair[1] == INVALID_HANDLE_VALUE) {
     217               0 :     CloseHandle(pair[0]);
     218               0 :     return -1;
     219                 :   }
     220               7 :   if (ConnectNamedPipe(pair[0], NULL) == FALSE) {
     221               7 :     DWORD error = GetLastError();
     222               7 :     if (error != ERROR_PIPE_CONNECTED) {
     223               0 :       CloseHandle(pair[0]);
     224               0 :       CloseHandle(pair[1]);
     225               0 :       return -1;
     226                 :     }
     227                 :   }
     228               7 :   return 0;
     229               7 : }
     230                 : 
     231               9 : int NaClClose(NaClHandle handle) {
     232               9 :   if (handle == NULL || handle == INVALID_HANDLE_VALUE) {
     233               0 :     return 0;
     234                 :   }
     235               9 :   return CloseHandle(handle) ? 0 : -1;
     236               9 : }
     237                 : 
     238                 : int NaClSendDatagram(NaClHandle handle, const NaClMessageHeader* message,
     239               5 :                      int flags) {
     240               5 :   ControlHeader header = { kEchoRequest, GetCurrentProcessId(), 0, 0 };
     241                 :   uint64_t remote_handles[NACL_HANDLE_COUNT_MAX];
     242                 :   uint32_t i;
     243                 : 
     244               5 :   if (NACL_HANDLE_COUNT_MAX < message->handle_count) {
     245               0 :     SetLastError(ERROR_INVALID_PARAMETER);
     246               0 :     return -1;
     247                 :   }
     248               5 :   if (!NaClMessageSizeIsValid(message)) {
     249               0 :     SetLastError(ERROR_INVALID_PARAMETER);
     250               0 :     return -1;
     251                 :   }
     252               5 :   if (0 < message->handle_count && message->handles) {
     253                 :     HANDLE target;
     254                 :     /*
     255                 :      * TODO(shiki): On Windows Vista, we can use GetNamedPipeClientProcessId()
     256                 :      * and GetNamedPipeServerProcessId() and probably we can remove
     257                 :      * kEchoRequest and kEchoResponse completely.
     258                 :      */
     259                 :     if (WriteAll(handle, &header, sizeof header) != sizeof header ||
     260                 :         ReadAll(handle, &header, sizeof header) != sizeof header ||
     261               3 :         header.command != kEchoResponse) {
     262               0 :       return -1;
     263                 :     }
     264               3 :     if (g_broker_duplicate_handle_func == NULL) {
     265               3 :       target = OpenProcess(PROCESS_DUP_HANDLE, FALSE, header.pid);
     266               3 :       if (target == NULL) {
     267               0 :         return -1;
     268                 :       }
     269                 :     }
     270               3 :     for (i = 0; i < message->handle_count; ++i) {
     271                 :       HANDLE temp_remote_handle;
     272                 :       bool success;
     273               3 :       if (g_broker_duplicate_handle_func != NULL) {
     274                 :         success = g_broker_duplicate_handle_func(message->handles[i],
     275                 :                                                  header.pid,
     276                 :                                                  &temp_remote_handle,
     277               0 :                                                  0, DUPLICATE_SAME_ACCESS);
     278               0 :       } else {
     279                 :         success = DuplicateHandle(GetCurrentProcess(), message->handles[i],
     280                 :                                   target, &temp_remote_handle,
     281               3 :                                   0, FALSE, DUPLICATE_SAME_ACCESS);
     282                 :       }
     283               3 :       if (!success) {
     284                 :         /*
     285                 :          * Send the kCancel message to revoke the handles duplicated
     286                 :          * so far in the remote peer.
     287                 :          */
     288               0 :         header.command = kCancel;
     289               0 :         header.handle_count = i;
     290               0 :         if (0 < i) {
     291               0 :           WriteAll(handle, &header, sizeof header);
     292               0 :           WriteAll(handle, remote_handles, sizeof(uint64_t) * i);
     293                 :         }
     294               0 :         if (g_broker_duplicate_handle_func == NULL) {
     295               0 :           CloseHandle(target);
     296                 :         }
     297               0 :         return -1;
     298                 :       }
     299               3 :       remote_handles[i] = (uint64_t) temp_remote_handle;
     300               3 :     }
     301               3 :     if (g_broker_duplicate_handle_func == NULL) {
     302               3 :       CloseHandle(target);
     303                 :     }
     304                 :   }
     305               5 :   header.command = kMessage;
     306               5 :   header.handle_count = message->handle_count;
     307               5 :   for (i = 0; i < message->iov_length; ++i) {
     308               5 :     if (UINT32_MAX - header.message_length < message->iov[i].length) {
     309               0 :       return -1;
     310                 :     }
     311               5 :     header.message_length += (uint32_t) message->iov[i].length;
     312               5 :   }
     313               5 :   if (WriteAll(handle, &header, sizeof header) != sizeof header) {
     314               1 :     return -1;
     315                 :   }
     316               5 :   for (i = 0; i < message->iov_length; ++i) {
     317                 :     if (WriteAll(handle, message->iov[i].base, message->iov[i].length) !=
     318               5 :         message->iov[i].length) {
     319               0 :       return -1;
     320                 :     }
     321               5 :   }
     322                 :   if (0 < message->handle_count && message->handles &&
     323                 :       WriteAll(handle,
     324                 :                remote_handles,
     325                 :                sizeof(uint64_t) * message->handle_count) !=
     326               5 :           sizeof(uint64_t) * message->handle_count) {
     327               0 :     return -1;
     328                 :   }
     329               5 :   return (int) header.message_length;
     330               5 : }
     331                 : 
     332                 : int NaClSendDatagramTo(const NaClMessageHeader* message, int flags,
     333               3 :                        const NaClSocketAddress* name) {
     334                 :   NaClHandle handle;
     335                 :   char pipe_name[kPipePathMax];
     336                 :   int timeout_ms;
     337                 :   int result;
     338                 : 
     339               3 :   if (NACL_HANDLE_COUNT_MAX < message->handle_count) {
     340               0 :     SetLastError(ERROR_INVALID_PARAMETER);
     341               0 :     return -1;
     342                 :   }
     343               3 :   if (!NaClMessageSizeIsValid(message)) {
     344               0 :     SetLastError(ERROR_INVALID_PARAMETER);
     345               0 :     return -1;
     346                 :   }
     347               3 :   if (!GetSocketName(name, pipe_name)) {
     348               0 :     return -1;
     349                 :   }
     350               3 :   timeout_ms = 10;
     351                 :   for (;;) {
     352                 :     handle = CreateFileW(ASCIIToWide(pipe_name).c_str(),
     353                 :                          GENERIC_READ | GENERIC_WRITE,
     354                 :                          0,              /* no sharing */
     355                 :                          NULL,           /* default security attributes */
     356                 :                          OPEN_EXISTING,  /* opens existing pipe */
     357                 :                          SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
     358               3 :                          NULL);          /* no template file */
     359               3 :     if (handle != INVALID_HANDLE_VALUE) {
     360               3 :       break;
     361                 :     }
     362                 : 
     363                 :     /* If the pipe is busy it means it exists, so we can try and wait. */
     364               1 :     if (GetLastError() != ERROR_PIPE_BUSY) {
     365               1 :       if (GetLastError() != ERROR_FILE_NOT_FOUND) {
     366               0 :         return -1;
     367                 :       } else {
     368                 :         /*
     369                 :          * Try to find the file using name with prefix (can be created
     370                 :          * by an old version of IMC library.
     371                 :          */
     372               1 :         if (!GetSocketNameWithOldPrefix(name, pipe_name)) {
     373               0 :           return -1;
     374                 :         }
     375                 :         handle = CreateFileW(ASCIIToWide(pipe_name).c_str(),
     376                 :                              GENERIC_READ | GENERIC_WRITE,
     377                 :                              0,              /* no sharing */
     378                 :                              NULL,           /* default security attributes */
     379                 :                              OPEN_EXISTING,  /* opens existing pipe */
     380                 :                              SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
     381               1 :                              NULL);          /* no template file */
     382               1 :         if (handle != INVALID_HANDLE_VALUE) {
     383               0 :           break;
     384                 :         }
     385               1 :         if (GetLastError() != ERROR_PIPE_BUSY) {
     386                 :           /* Could not find the pipe - nothing to do */
     387               1 :           return -1;
     388                 :         }
     389                 :       }
     390               0 :       break;
     391                 :     }
     392               0 :     if (flags & NACL_DONT_WAIT) {
     393               0 :       SetLastError(ERROR_PIPE_LISTENING);
     394               0 :       return -1;
     395                 :     }
     396                 :     /* Cannot call WaitNamedPipe here because it's blocked by Chrome sandbox. */
     397               0 :     Sleep(timeout_ms);
     398               0 :     timeout_ms *= 2;
     399               0 :     if (timeout_ms > kDefaultTimeoutMilliSeconds) {
     400               0 :       timeout_ms = kDefaultTimeoutMilliSeconds;
     401                 :     }
     402               0 :   }
     403               3 :   result = NaClSendDatagram(handle, message, flags);
     404               3 :   CloseHandle(handle);
     405               3 :   return result;
     406               3 : }
     407                 : 
     408                 : static int ReceiveDatagram(NaClHandle handle, NaClMessageHeader* message,
     409               5 :                            int flags, bool bound_socket) {
     410                 :   ControlHeader header;
     411               5 :   int result = -1;
     412               5 :   bool dontPeek = false;
     413                 :   uint32_t i;
     414                 :  Repeat:
     415               5 :   if ((flags & NACL_DONT_WAIT) && !dontPeek) {
     416                 :     DWORD len;
     417                 :     DWORD total;
     418               0 :     if (PeekNamedPipe(handle, &header, sizeof header, &len, &total, NULL)) {
     419               0 :       if (len < sizeof header) {
     420               0 :         SetLastError(ERROR_PIPE_LISTENING);
     421               0 :       } else {
     422               0 :         switch (header.command) {
     423                 :         case kEchoRequest:
     424                 :           /*
     425                 :            * Send back the process id to the remote peer to duplicate handles.
     426                 :            * TODO(shiki) : It might be better to keep remote pid by the initial
     427                 :            *               handshake rather than send kEchoRequest each time
     428                 :            *               before duplicating handles.
     429                 :            */
     430               0 :           if (ReadAll(handle, &header, sizeof header) == sizeof header) {
     431               0 :             header.command = kEchoResponse;
     432               0 :             header.pid = GetCurrentProcessId();
     433               0 :             WriteAll(handle, &header, sizeof header);
     434               0 :             if (bound_socket) {
     435                 :               /* We must not close this connection. */
     436               0 :               dontPeek = true;
     437                 :             }
     438               0 :             goto Repeat;
     439                 :           }
     440               0 :           break;
     441                 :         case kEchoResponse:
     442               0 :           SkipFile(handle, sizeof header);
     443               0 :           goto Repeat;
     444                 :           break;
     445                 :         case kMessage:
     446               0 :           if (header.message_length + sizeof header <= total) {
     447               0 :             if (flags & NACL_DONT_WAIT) {
     448               0 :               flags &= ~NACL_DONT_WAIT;
     449               0 :               goto Repeat;
     450                 :             }
     451               0 :             result = (int) header.message_length;
     452               0 :           } else {
     453               0 :             SetLastError(ERROR_PIPE_LISTENING);
     454                 :           }
     455               0 :           break;
     456                 :         case kCancel:
     457                 :           if (sizeof header + sizeof(uint64_t) * header.handle_count <= len &&
     458               0 :               ReadAll(handle, &header, sizeof header) == sizeof header) {
     459               0 :             SkipHandles(handle, header.handle_count);
     460               0 :             goto Repeat;
     461                 :           }
     462                 :           break;
     463                 :         default:
     464                 :           break;
     465                 :         }
     466                 :       }
     467               0 :     }
     468               5 :   } else if (ReadAll(handle, &header, sizeof header) == sizeof header) {
     469               5 :     dontPeek = false;
     470               5 :     switch (header.command) {
     471                 :     case kEchoRequest:
     472               3 :       header.command = kEchoResponse;
     473               3 :       header.pid = GetCurrentProcessId();
     474               3 :       WriteAll(handle, &header, sizeof header);
     475               3 :       goto Repeat;
     476                 :       break;
     477                 :     case kEchoResponse:
     478               0 :       goto Repeat;
     479                 :       break;
     480                 :     case kMessage: {
     481               5 :       uint32_t total_message_bytes = header.message_length;
     482               5 :       size_t count = 0;
     483               5 :       message->flags = 0;
     484               5 :       for (i = 0;
     485               5 :            i < message->iov_length && count < header.message_length;
     486               5 :            ++i) {
     487               5 :         NaClIOVec* iov = &message->iov[i];
     488               5 :         uint32_t len = std::min((uint32_t) iov->length, total_message_bytes);
     489               5 :         if (ReadAll(handle, iov->base, len) != len) {
     490               0 :           break;
     491                 :         }
     492               5 :         total_message_bytes -= len;
     493               5 :         count += len;
     494               5 :       }
     495               5 :       if (count < header.message_length) {
     496               0 :         if (SkipFile(handle, header.message_length - count) == FALSE) {
     497               0 :           break;
     498                 :         }
     499               0 :         message->flags |= NACL_MESSAGE_TRUNCATED;
     500                 :       }
     501               5 :       if (0 < message->handle_count && message->handles) {
     502                 :         uint64_t received_handles[NACL_HANDLE_COUNT_MAX];
     503                 :         message->handle_count = std::min(message->handle_count,
     504               5 :                                          header.handle_count);
     505                 :         if (ReadAll(handle, received_handles,
     506                 :                     message->handle_count * sizeof(uint64_t)) !=
     507               5 :             message->handle_count * sizeof(uint64_t)) {
     508               0 :           break;
     509                 :         }
     510               5 :         for (i = 0; i < message->handle_count; ++i) {
     511               3 :           message->handles[i] = (HANDLE) received_handles[i];
     512               5 :         }
     513                 :       } else {
     514               0 :         message->handle_count = 0;
     515                 :       }
     516               5 :       if (message->handle_count < header.handle_count) {
     517                 :         if (SkipHandles(handle, header.handle_count - message->handle_count) ==
     518               0 :             FALSE) {
     519               0 :           break;
     520                 :         }
     521               0 :         message->flags |= NACL_HANDLES_TRUNCATED;
     522                 :       }
     523               5 :       result = (int) count;
     524               5 :       break;
     525                 :     }
     526                 :     case kCancel:
     527               0 :       SkipHandles(handle, header.handle_count);
     528               0 :       goto Repeat;
     529                 :       break;
     530                 :     default:
     531                 :       break;
     532                 :     }
     533                 :   }
     534               5 :   return result;
     535               5 : }
     536                 : 
     537                 : int NaClReceiveDatagram(NaClHandle handle, NaClMessageHeader* message,
     538               5 :                         int flags) {
     539                 :   DWORD state;
     540               5 :   if (!NaClMessageSizeIsValid(message)) {
     541               0 :     SetLastError(ERROR_INVALID_PARAMETER);
     542               0 :     return -1;
     543                 :   }
     544                 : 
     545                 :   /*
     546                 :    * If handle is a bound socket, it is a named pipe in non-blocking mode.
     547                 :    * Set is_bound_socket to true if handle has been created by BoundSocket().
     548                 :    */
     549               5 :   if (!GetNamedPipeHandleState(handle, &state, NULL, NULL, NULL, NULL, NULL)) {
     550               0 :     return -1;
     551                 :   }
     552                 : 
     553               5 :   if (!(state & PIPE_NOWAIT)) {
     554                 :     /* handle is a connected socket. */
     555               5 :     return ReceiveDatagram(handle, message, flags, false);
     556                 :   }
     557                 : 
     558                 :   /* handle is a bound socket. */
     559                 :   for (;;) {
     560               3 :     if (ConnectNamedPipe(handle, NULL)) {
     561                 :       /*
     562                 :        * Note ConnectNamedPipe() for a handle in non-blocking mode returns a
     563                 :        * nonzero value just to indicate that the pipe is now available to be
     564                 :        * connected.
     565                 :        */
     566               3 :       continue;
     567                 :     }
     568               3 :     switch (GetLastError()) {
     569                 :     case ERROR_PIPE_LISTENING: {
     570                 :       /* Set handle to blocking mode */
     571               3 :       DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
     572               3 :       if (flags & NACL_DONT_WAIT) {
     573               0 :         return -1;
     574                 :       }
     575               3 :       SetNamedPipeHandleState(handle, &mode, NULL, NULL);
     576               3 :       break;
     577                 :     }
     578                 :     case ERROR_PIPE_CONNECTED: {
     579                 :       /* Set handle to blocking mode */
     580               3 :       DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
     581                 :       int result;
     582               3 :       SetNamedPipeHandleState(handle, &mode, NULL, NULL);
     583               3 :       result = ReceiveDatagram(handle, message, flags, true);
     584               3 :       FlushFileBuffers(handle);
     585                 :       /* Set handle back to non-blocking mode. */
     586               3 :       mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
     587               3 :       SetNamedPipeHandleState(handle, &mode, NULL, NULL);
     588               3 :       DisconnectNamedPipe(handle);
     589               3 :       if (result == -1 && GetLastError() == ERROR_BROKEN_PIPE) {
     590               0 :         if (flags & NACL_DONT_WAIT) {
     591               0 :           SetLastError(ERROR_PIPE_LISTENING);
     592               0 :           return result;
     593                 :         }
     594               0 :       } else {
     595               3 :         return result;
     596                 :       }
     597               0 :       break;
     598                 :     }
     599                 :     default:
     600               0 :       return -1;
     601                 :       break;
     602                 :     }
     603               3 :   }
     604               5 : }

Generated by: LCOV version 1.7