diff options
author | sehr@google.com <sehr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-24 16:14:53 +0000 |
---|---|---|
committer | sehr@google.com <sehr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-24 16:14:53 +0000 |
commit | 0840cc764d0f0b693d3762c356b7d35e58d343af (patch) | |
tree | 8f1f90ef17b8e395f27f239beaf86ce9b5af6467 /base/sync_socket_win.cc | |
parent | 160673757540777e7db373c56b61673f05870c99 (diff) | |
download | chromium_src-0840cc764d0f0b693d3762c356b7d35e58d343af.zip chromium_src-0840cc764d0f0b693d3762c356b7d35e58d343af.tar.gz chromium_src-0840cc764d0f0b693d3762c356b7d35e58d343af.tar.bz2 |
This adds the first version of SyncSocket to base, along with a trivial unittest.
SyncSocket provides a blocking send/receive that can be used for synchronization.
Review URL: http://codereview.chromium.org/418004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32927 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/sync_socket_win.cc')
-rw-r--r-- | base/sync_socket_win.cc | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc new file mode 100644 index 0000000..b591bb0 --- /dev/null +++ b/base/sync_socket_win.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/sync_socket.h" +#include <limits.h> +#include <stdio.h> +#include <windows.h> +#include <sys/types.h> +#include "base/atomicops.h" +#include "base/logging.h" + + +namespace base { + +namespace { +// This prefix used to be appended to pipe names for pipes +// created in CreatePair. +const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\chrome.sync."; +const size_t kPipePrefixSize = arraysize(kPipePrefix); +const size_t kPathMax = 28; // print length of process id + pair count. +const size_t kPipePathMax = kPipePrefixSize + kPathMax + 1; + +// To avoid users sending negative message lengths to Send/Receive +// we clamp message lengths, which are size_t, to no more than INT_MAX. +const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); + +const int kOutBufferSize = 4096; +const int kInBufferSize = 4096; +const int kDefaultTimeoutMilliSeconds = 1000; + +static const SyncSocket::Handle kInvalidHandle = INVALID_HANDLE_VALUE; + +} // namespace + +bool SyncSocket::CreatePair(SyncSocket* pair[2]) { + Handle handles[2]; + SyncSocket* tmp_sockets[2]; + + // Create the two SyncSocket objects first to avoid ugly cleanup issues. + tmp_sockets[0] = new SyncSocket(kInvalidHandle); + if (tmp_sockets[0] == NULL) { + return false; + } + tmp_sockets[1] = new SyncSocket(kInvalidHandle); + if (tmp_sockets[1] == NULL) { + delete tmp_sockets[0]; + return false; + } + + wchar_t name[kPipePathMax]; + do { + unsigned int rnd_name; + if (rand_s(&rnd_name) != 0) + return false; + swprintf(name, kPipePathMax, L"%s%u.%lu", + kPipePrefix, GetCurrentProcessId(), + rnd_name); + handles[0] = CreateNamedPipeW( + name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, + 1, + kOutBufferSize, + kInBufferSize, + kDefaultTimeoutMilliSeconds, + NULL); + if (handles[0] == INVALID_HANDLE_VALUE && + GetLastError() != ERROR_ACCESS_DENIED && + GetLastError() != ERROR_PIPE_BUSY) { + return false; + } + } while (handles[0] == INVALID_HANDLE_VALUE); + handles[1] = CreateFileW(name, + GENERIC_READ | GENERIC_WRITE, + 0, // no sharing. + NULL, // default security attributes. + OPEN_EXISTING, // opens existing pipe. + SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, + // no impersonation. + NULL); // no template file. + if (handles[1] == INVALID_HANDLE_VALUE) { + CloseHandle(handles[0]); + return false; + } + if (ConnectNamedPipe(handles[0], NULL) == FALSE) { + DWORD error = GetLastError(); + if (error != ERROR_PIPE_CONNECTED) { + CloseHandle(handles[0]); + CloseHandle(handles[1]); + return false; + } + } + // Copy the handles out for successful return. + tmp_sockets[0]->handle_ = handles[0]; + pair[0] = tmp_sockets[0]; + tmp_sockets[1]->handle_ = handles[1]; + pair[1] = tmp_sockets[1]; + return true; +} + +bool SyncSocket::Close() { + if (handle_ == kInvalidHandle) { + return false; + } + BOOL retval = CloseHandle(handle_); + handle_ = kInvalidHandle; + return retval ? true : false; +} + +size_t SyncSocket::Send(const void* buffer, size_t length) { + DCHECK(length <= kMaxMessageLength); + size_t count = 0; + while (count < length) { + DWORD len; + // The following statement is for 64 bit portability. + DWORD chunk = static_cast<DWORD>( + ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); + if (WriteFile(handle_, static_cast<const char*>(buffer) + count, + chunk, &len, NULL) == FALSE) { + return (0 < count) ? count : 0; + } + count += len; + } + return count; +} + +size_t SyncSocket::Receive(void* buffer, size_t length) { + DCHECK(length <= kMaxMessageLength); + size_t count = 0; + while (count < length) { + DWORD len; + DWORD chunk = static_cast<DWORD>( + ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); + if (ReadFile(handle_, static_cast<char*>(buffer) + count, + chunk, &len, NULL) == FALSE) { + return (0 < count) ? count : 0; + } + count += len; + } + return count; +} + +} // namespace base |