ipc/unixsocket/ConnectionOrientedSocket.cpp
author Michael Comella <michael.l.comella@gmail.com>
Tue, 15 Sep 2015 16:46:58 -0700
changeset 266944 ed8188590f14b1aae2e4f44c8196994f375a99f4
parent 253778 e9f9b39c43317d8de56a49427ccbdf27b9647ad0
child 295765 413335e6452af2fb0768056b652953ca5da0fe96
permissions -rw-r--r--
Bug 1201206 - Correct menu button background on 2.3. r=mhaigh One fear is that different devices set different menu colors and text colors. Since we're using the default text color and set an explicit menu color, the text color may not look good on these devices. I was unable to find a way to override the menu text color. It seems the best way to find out if this is a problem is to land it and test though!

/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "ConnectionOrientedSocket.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
#include "UnixSocketConnector.h"

namespace mozilla {
namespace ipc {

//
// ConnectionOrientedSocketIO
//

ConnectionOrientedSocketIO::ConnectionOrientedSocketIO(
  MessageLoop* aConsumerLoop,
  MessageLoop* aIOLoop,
  int aFd, ConnectionStatus aConnectionStatus,
  UnixSocketConnector* aConnector)
  : DataSocketIO(aConsumerLoop)
  , UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
  , mConnector(aConnector)
  , mPeerAddressLength(0)
{
  MOZ_ASSERT(mConnector);

  MOZ_COUNT_CTOR_INHERITED(ConnectionOrientedSocketIO, DataSocketIO);
}

ConnectionOrientedSocketIO::ConnectionOrientedSocketIO(
  MessageLoop* aConsumerLoop,
  MessageLoop* aIOLoop,
  UnixSocketConnector* aConnector)
  : DataSocketIO(aConsumerLoop)
  , UnixSocketWatcher(aIOLoop)
  , mConnector(aConnector)
  , mPeerAddressLength(0)
{
  MOZ_ASSERT(mConnector);

  MOZ_COUNT_CTOR_INHERITED(ConnectionOrientedSocketIO, DataSocketIO);
}

ConnectionOrientedSocketIO::~ConnectionOrientedSocketIO()
{
  MOZ_COUNT_DTOR_INHERITED(ConnectionOrientedSocketIO, DataSocketIO);
}

nsresult
ConnectionOrientedSocketIO::Accept(int aFd,
                                   const struct sockaddr* aPeerAddress,
                                   socklen_t aPeerAddressLength)
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTING);

  SetSocket(aFd, SOCKET_IS_CONNECTED);

  // Address setup
  mPeerAddressLength = aPeerAddressLength;
  memcpy(&mPeerAddress, aPeerAddress, mPeerAddressLength);

  // Signal success and start data transfer
  OnConnected();

  return NS_OK;
}

nsresult
ConnectionOrientedSocketIO::Connect()
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
  MOZ_ASSERT(!IsOpen());

  struct sockaddr* peerAddress =
    reinterpret_cast<struct sockaddr*>(&mPeerAddress);
  mPeerAddressLength = sizeof(mPeerAddress);

  int fd;
  nsresult rv = mConnector->CreateStreamSocket(peerAddress,
                                               &mPeerAddressLength,
                                               fd);
  if (NS_FAILED(rv)) {
    // Tell the consumer thread we've errored
    GetConsumerThread()->PostTask(
      FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR));
    return NS_ERROR_FAILURE;
  }

  SetFd(fd);

  // calls OnConnected() on success, or OnError() otherwise
  rv = UnixSocketWatcher::Connect(peerAddress, mPeerAddressLength);

  if (NS_FAILED(rv)) {
    return rv;
  }

  return NS_OK;
}

void
ConnectionOrientedSocketIO::Send(UnixSocketIOBuffer* aBuffer)
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());

  EnqueueData(aBuffer);
  AddWatchers(WRITE_WATCHER, false);
}

// |UnixSocketWatcher|

void
ConnectionOrientedSocketIO::OnSocketCanReceiveWithoutBlocking()
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984

  ssize_t res = ReceiveData(GetFd());
  if (res < 0) {
    /* I/O error */
    RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
  } else if (!res) {
    /* EOF or peer shutdown */
    RemoveWatchers(READ_WATCHER);
  }
}

void
ConnectionOrientedSocketIO::OnSocketCanSendWithoutBlocking()
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
  MOZ_ASSERT(!IsShutdownOnIOThread());

  nsresult rv = SendPendingData(GetFd());
  if (NS_FAILED(rv)) {
    return;
  }

  if (HasPendingData()) {
    AddWatchers(WRITE_WATCHER, false);
  }
}

void
ConnectionOrientedSocketIO::OnConnected()
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);

  GetConsumerThread()->PostTask(
    FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS));

  AddWatchers(READ_WATCHER, true);
  if (HasPendingData()) {
    AddWatchers(WRITE_WATCHER, false);
  }
}

void
ConnectionOrientedSocketIO::OnListening()
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());

  NS_NOTREACHED("Invalid call to |ConnectionOrientedSocketIO::OnListening|");
}

void
ConnectionOrientedSocketIO::OnError(const char* aFunction, int aErrno)
{
  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());

  UnixFdWatcher::OnError(aFunction, aErrno);

  // Clean up watchers, status, fd
  Close();

  // Tell the consumer thread we've errored
  GetConsumerThread()->PostTask(
    FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR));
}

//
// ConnectionOrientedSocket
//

ConnectionOrientedSocket::ConnectionOrientedSocket()
{
  MOZ_COUNT_CTOR_INHERITED(ConnectionOrientedSocket, DataSocket);
}

ConnectionOrientedSocket::~ConnectionOrientedSocket()
{
  MOZ_COUNT_DTOR_INHERITED(ConnectionOrientedSocket, DataSocket);
}

}
}