sync_socket_win.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/sync_socket.h"
6#include <limits.h>
7#include <stdio.h>
8#include <windows.h>
9#include <sys/types.h>
10#include "base/logging.h"
11
12
13namespace base {
14
15namespace {
16// This prefix used to be appended to pipe names for pipes
17// created in CreatePair.
18const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\chrome.sync.";
19const size_t kPipePrefixSize = arraysize(kPipePrefix);
20const size_t kPathMax = 28;  // print length of process id + pair count.
21const size_t kPipePathMax = kPipePrefixSize + kPathMax + 1;
22
23// To avoid users sending negative message lengths to Send/Receive
24// we clamp message lengths, which are size_t, to no more than INT_MAX.
25const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
26
27const int kOutBufferSize = 4096;
28const int kInBufferSize = 4096;
29const int kDefaultTimeoutMilliSeconds = 1000;
30
31static const SyncSocket::Handle kInvalidHandle = INVALID_HANDLE_VALUE;
32
33}  // namespace
34
35bool SyncSocket::CreatePair(SyncSocket* pair[2]) {
36  Handle handles[2];
37  SyncSocket* tmp_sockets[2];
38
39  // Create the two SyncSocket objects first to avoid ugly cleanup issues.
40  tmp_sockets[0] = new SyncSocket(kInvalidHandle);
41  if (tmp_sockets[0] == NULL) {
42    return false;
43  }
44  tmp_sockets[1] = new SyncSocket(kInvalidHandle);
45  if (tmp_sockets[1] == NULL) {
46    delete tmp_sockets[0];
47    return false;
48  }
49
50  wchar_t name[kPipePathMax];
51  do {
52    unsigned int rnd_name;
53    if (rand_s(&rnd_name) != 0)
54      return false;
55    swprintf(name, kPipePathMax, L"%s%u.%lu",
56             kPipePrefix, GetCurrentProcessId(),
57             rnd_name);
58    handles[0] = CreateNamedPipeW(
59        name,
60        PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
61        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
62        1,
63        kOutBufferSize,
64        kInBufferSize,
65        kDefaultTimeoutMilliSeconds,
66        NULL);
67    if (handles[0] == INVALID_HANDLE_VALUE &&
68        GetLastError() != ERROR_ACCESS_DENIED &&
69        GetLastError() != ERROR_PIPE_BUSY) {
70      return false;
71    }
72  } while (handles[0] == INVALID_HANDLE_VALUE);
73  handles[1] = CreateFileW(name,
74                           GENERIC_READ | GENERIC_WRITE,
75                           0,              // no sharing.
76                           NULL,           // default security attributes.
77                           OPEN_EXISTING,  // opens existing pipe.
78                           SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
79                                           // no impersonation.
80                           NULL);          // no template file.
81  if (handles[1] == INVALID_HANDLE_VALUE) {
82    CloseHandle(handles[0]);
83    return false;
84  }
85  if (ConnectNamedPipe(handles[0], NULL) == FALSE) {
86    DWORD error = GetLastError();
87    if (error != ERROR_PIPE_CONNECTED) {
88      CloseHandle(handles[0]);
89      CloseHandle(handles[1]);
90      return false;
91    }
92  }
93  // Copy the handles out for successful return.
94  tmp_sockets[0]->handle_ = handles[0];
95  pair[0] = tmp_sockets[0];
96  tmp_sockets[1]->handle_ = handles[1];
97  pair[1] = tmp_sockets[1];
98  return true;
99}
100
101bool SyncSocket::Close() {
102  if (handle_ == kInvalidHandle) {
103    return false;
104  }
105  BOOL retval = CloseHandle(handle_);
106  handle_ = kInvalidHandle;
107  return retval ? true : false;
108}
109
110size_t SyncSocket::Send(const void* buffer, size_t length) {
111  DCHECK(length <= kMaxMessageLength);
112  size_t count = 0;
113  while (count < length) {
114    DWORD len;
115    // The following statement is for 64 bit portability.
116    DWORD chunk = static_cast<DWORD>(
117      ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
118    if (WriteFile(handle_, static_cast<const char*>(buffer) + count,
119                  chunk, &len, NULL) == FALSE) {
120      return (0 < count) ? count : 0;
121    }
122    count += len;
123  }
124  return count;
125}
126
127size_t SyncSocket::Receive(void* buffer, size_t length) {
128  DCHECK(length <= kMaxMessageLength);
129  size_t count = 0;
130  while (count < length) {
131    DWORD len;
132    DWORD chunk = static_cast<DWORD>(
133      ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
134    if (ReadFile(handle_, static_cast<char*>(buffer) + count,
135                 chunk, &len, NULL) == FALSE) {
136      return (0 < count) ? count : 0;
137    }
138    count += len;
139  }
140  return count;
141}
142
143size_t SyncSocket::Peek() {
144  DWORD available = 0;
145  PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL);
146  return available;
147}
148
149}  // namespace base
150