sync_socket_posix.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sync_socket.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ioctl.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_SOLARIS)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/filio.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// To avoid users sending negative message lengths to Send/Receive
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we clamp message lengths, which are size_t, to no more than INT_MAX.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncSocket::~SyncSocket() {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Close();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_a != socket_b);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_a->handle_ == kInvalidHandle);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_b->handle_ == kInvalidHandle);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nosigpipe = 1;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_MACOSX)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Handle handles[2] = { kInvalidHandle, kInvalidHandle };
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto cleanup;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On OSX an attempt to read or write to a closed socket may generate a
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SIGPIPE rather than returning -1.  setsockopt will shut this off.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &nosigpipe, sizeof nosigpipe) ||
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &nosigpipe, sizeof nosigpipe)) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto cleanup;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy the handles out for successful return.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_a->handle_ = handles[0];
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_b->handle_ = handles[1];
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cleanup:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handles[0] != kInvalidHandle) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(close(handles[0])) < 0)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "close";
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handles[1] != kInvalidHandle) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(close(handles[1])) < 0)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "close";
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncSocket::Close() {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handle_ == kInvalidHandle) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int retval = HANDLE_EINTR(close(handle_));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (retval < 0)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPLOG(ERROR) << "close";
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handle_ = kInvalidHandle;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (retval == 0);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t SyncSocket::Send(const void* buffer, size_t length) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(length, kMaxMessageLength);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* charbuffer = static_cast<const char*>(buffer);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int len = file_util::WriteFileDescriptor(handle_, charbuffer, length);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (len == -1) ? 0 : static_cast<size_t>(len);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t SyncSocket::Receive(void* buffer, size_t length) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(length, kMaxMessageLength);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* charbuffer = static_cast<char*>(buffer);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_util::ReadFromFD(handle_, charbuffer, length))
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return length;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t SyncSocket::Peek() {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int number_chars;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (-1 == ioctl(handle_, FIONREAD, &number_chars)) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is an error in ioctl, signal that the channel would block.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (size_t) number_chars;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CancelableSyncSocket::CancelableSyncSocket() {}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CancelableSyncSocket::CancelableSyncSocket(Handle handle)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : SyncSocket(handle) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CancelableSyncSocket::Shutdown() {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  long flags = 0;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  flags = fcntl(handle_, F_GETFL, NULL);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set the socket to non-blocking mode for sending if its original mode
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is blocking.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fcntl(handle_, F_SETFL, flags | O_NONBLOCK);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t len = SyncSocket::Send(buffer, length);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Restore the original flags.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fcntl(handle_, F_SETFL, flags);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return len;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      CancelableSyncSocket* socket_b) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SyncSocket::CreatePair(socket_a, socket_b);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
155