blob: 1f65dd449ba30e03d8b8bec0f3a415bece4560fb [file] [log] [blame]
// Copyright (c) 2012 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 "net/base/stream_listen_socket.h"
#if defined(OS_WIN)
// winsock2.h must be included first in order to ensure it is included before
// windows.h.
#include <winsock2.h>
#elif defined(OS_POSIX)
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "net/base/net_errors.h"
#elif defined(OS_STARBOARD)
#include "starboard/socket.h"
#endif
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/sys_byteorder.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
using std::string;
#if defined(OS_WIN)
typedef int socklen_t;
#endif // defined(OS_WIN)
namespace net {
namespace {
const int kReadBufSize = 4096;
#if defined(__LB_PS4__) || defined(__LB_LINUX__)
// Don't send SIGPIPE when the other end disconnects.
// We will still receive an EPIPE as expected.
const int kDefaultMsgFlags = MSG_NOSIGNAL;
#else
const int kDefaultMsgFlags = 0;
#endif
} // namespace
#if defined(OS_WIN)
const SocketDescriptor StreamListenSocket::kInvalidSocket = INVALID_SOCKET;
const int StreamListenSocket::kSocketError = SOCKET_ERROR;
#elif defined(OS_POSIX)
const SocketDescriptor StreamListenSocket::kInvalidSocket = -1;
const int StreamListenSocket::kSocketError = -1;
#elif defined(OS_STARBOARD)
const SocketDescriptor StreamListenSocket::kInvalidSocket = kSbSocketInvalid;
const int StreamListenSocket::kSocketError = -1;
#endif
StreamListenSocket::StreamListenSocket(SocketDescriptor s,
StreamListenSocket::Delegate* del)
: socket_delegate_(del),
socket_(s),
reads_paused_(false),
has_pending_reads_(false) {
#if defined(OS_WIN)
socket_event_ = WSACreateEvent();
// TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT.
WatchSocket(NOT_WAITING);
#elif defined(OS_POSIX)
wait_state_ = NOT_WAITING;
#elif defined(OS_STARBOARD)
wait_state_ = NOT_WAITING;
#endif
}
StreamListenSocket::~StreamListenSocket() {
#if defined(OS_WIN)
if (socket_event_) {
WSACloseEvent(socket_event_);
socket_event_ = WSA_INVALID_EVENT;
}
#endif
CloseSocket(socket_);
}
void StreamListenSocket::Send(const char* bytes, int len,
bool append_linefeed) {
SendInternal(bytes, len);
if (append_linefeed)
SendInternal("\r\n", 2);
}
void StreamListenSocket::Send(const string& str, bool append_linefeed) {
Send(str.data(), static_cast<int>(str.length()), append_linefeed);
}
int StreamListenSocket::GetLocalAddress(IPEndPoint* address) {
#if defined(OS_STARBOARD)
SbSocketAddress sb_address;
if (!SbSocketGetLocalAddress(socket_, &sb_address)) {
return ERR_FAILED;
}
if (!address->FromSbSocketAddress(&sb_address)) {
return ERR_FAILED;
}
return OK;
#else // defined(OS_STARBOARD)
SockaddrStorage storage;
if (getsockname(socket_, storage.addr, &storage.addr_len)) {
#if defined(OS_WIN)
int err = WSAGetLastError();
#else
int err = errno;
#endif
return MapSystemError(err);
}
if (!address->FromSockAddr(storage.addr, storage.addr_len))
return ERR_FAILED;
return OK;
#endif // defined(OS_STARBOARD)
}
SocketDescriptor StreamListenSocket::AcceptSocket() {
#if defined(OS_STARBOARD)
SocketDescriptor conn = SbSocketAccept(socket_);
#else
SocketDescriptor conn = HANDLE_EINTR(accept(socket_, NULL, NULL));
#endif
if (conn == kInvalidSocket)
LOG(ERROR) << "Error accepting connection.";
else
SetNonBlocking(conn);
return conn;
}
void StreamListenSocket::SendInternal(const char* bytes, int len) {
char* send_buf = const_cast<char *>(bytes);
int len_left = len;
while (true) {
#if defined(OS_STARBOARD)
int sent = SbSocketSendTo(socket_, send_buf, len_left, NULL);
#else
int sent = HANDLE_EINTR(
send(socket_, send_buf, len_left, kDefaultMsgFlags));
#endif
if (sent == len_left) { // A shortcut to avoid extraneous checks.
break;
}
// __LB_SHELL__: In some consoles |sent| might return the actual error code,
// and so can be even lower than the native |kSocketError|.
COMPILE_ASSERT(kSocketError < 0, native_socket_error_should_be_negative);
if (sent <= kSocketError) {
#if defined(OS_WIN)
if (WSAGetLastError() != WSAEWOULDBLOCK) {
LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
#elif defined(OS_STARBOARD)
if (SbSocketGetLastError(socket_) != kSbSocketPending) {
LOG(ERROR) << "SbSocketSendTo failed: error = "
<< SbSocketGetLastError(socket_);
#elif defined(__LB_SHELL__)
if (!lb_net_would_block()) {
LOG(ERROR) << "send failed: errno==" << lb_net_errno();
#elif defined(OS_POSIX)
if (errno != EWOULDBLOCK && errno != EAGAIN) {
LOG(ERROR) << "send failed: errno==" << errno;
#endif
break;
}
// Otherwise we would block, and now we have to wait for a retry.
// Fall through to PlatformThread::YieldCurrentThread()
} else {
// sent != len_left according to the shortcut above.
// Shift the buffer start and send the remainder after a short while.
send_buf += sent;
len_left -= sent;
}
base::PlatformThread::YieldCurrentThread();
}
}
void StreamListenSocket::Listen() {
#if defined(OS_STARBOARD)
SbSocketListen(socket_);
WatchSocket(WAITING_ACCEPT);
#else // defined(OS_STARBOARD)
int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
if (listen(socket_, backlog) == -1) {
// TODO(erikkay): error handling.
LOG(ERROR) << "Could not listen on socket.";
return;
}
#if defined(OS_POSIX)
WatchSocket(WAITING_ACCEPT);
#endif
#endif // defined(OS_STARBOARD)
}
void StreamListenSocket::Read() {
char buf[kReadBufSize + 1]; // +1 for null termination.
#if defined(OS_STARBOARD)
int len;
do {
len = SbSocketReceiveFrom(socket_, buf, kReadBufSize, NULL);
if (len < 0) {
SbSocketError error = SbSocketGetLastError(socket_);
break;
}
if (len == 0) {
Close();
} else {
DCHECK_LT(0, len);
DCHECK_GE(kReadBufSize, len);
buf[len] = 0; // We already create a buffer with +1 length.
socket_delegate_->DidRead(this, buf, len);
}
} while (len == kReadBufSize);
#else // defined(OS_STARBOARD)
int len;
do {
len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, kDefaultMsgFlags));
if (len == kSocketError) {
#if defined(OS_WIN)
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK) {
#elif defined(OS_POSIX)
if (errno == EWOULDBLOCK || errno == EAGAIN) {
#endif
break;
} else {
// TODO(ibrar): some error handling required here.
break;
}
} else if (len == 0) {
// In Windows, Close() is called by OnObjectSignaled. In POSIX, we need
// to call it here.
#if defined(OS_POSIX)
Close();
#endif
} else {
#if defined(__LB_SHELL__)
if (len < 0) {
// Some platforms return a negative error code for length instead of a
// simple -1. Thus, we must check it in the len < 0 case.
if (!lb_net_would_block()) {
Close();
}
break;
}
#endif
// TODO(ibrar): maybe change DidRead to take a length instead.
DCHECK_GT(len, 0);
DCHECK_LE(len, kReadBufSize);
buf[len] = 0; // Already create a buffer with +1 length.
socket_delegate_->DidRead(this, buf, len);
}
} while (len == kReadBufSize);
#endif // defined(OS_STARBOARD)
}
void StreamListenSocket::Close() {
#if defined(OS_POSIX) || defined(OS_STARBOARD)
if (wait_state_ == NOT_WAITING)
return;
wait_state_ = NOT_WAITING;
#endif
UnwatchSocket();
socket_delegate_->DidClose(this);
}
void StreamListenSocket::CloseSocket(SocketDescriptor s) {
if (s && s != kInvalidSocket) {
UnwatchSocket();
#if defined(OS_WIN)
closesocket(s);
#elif defined(OS_STARBOARD)
SbSocketDestroy(s);
#elif defined(__LB_SHELL__)
lb_close_socket(s);
#elif defined(OS_POSIX)
close(s);
#endif
}
}
void StreamListenSocket::WatchSocket(WaitState state) {
#if defined(OS_WIN)
WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ);
watcher_.StartWatching(socket_event_, this);
#elif defined(OS_STARBOARD)
MessageLoopForIO::current()->Watch(
socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
wait_state_ = state;
#elif defined(__LB_SHELL__) && !defined(__LB_ANDROID__)
watcher_.StartWatching(socket_, base::MessagePumpShell::WATCH_READ, this);
wait_state_ = state;
#elif defined(OS_POSIX)
// Implicitly calls StartWatchingFileDescriptor().
MessageLoopForIO::current()->WatchFileDescriptor(
socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
wait_state_ = state;
#endif
}
void StreamListenSocket::UnwatchSocket() {
#if defined(OS_WIN)
watcher_.StopWatching();
#elif defined(OS_STARBOARD)
watcher_.StopWatchingSocket();
#elif defined(__LB_SHELL__) && !defined(__LB_ANDROID__)
watcher_.StopWatching();
#elif defined(OS_POSIX)
watcher_.StopWatchingFileDescriptor();
#endif
}
// TODO(ibrar): We can add these functions into OS dependent files.
#if defined(OS_WIN)
// MessageLoop watcher callback.
void StreamListenSocket::OnObjectSignaled(HANDLE object) {
WSANETWORKEVENTS ev;
if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) {
// TODO
return;
}
// The object was reset by WSAEnumNetworkEvents. Watch for the next signal.
watcher_.StartWatching(object, this);
if (ev.lNetworkEvents == 0) {
// Occasionally the event is set even though there is no new data.
// The net seems to think that this is ignorable.
return;
}
if (ev.lNetworkEvents & FD_ACCEPT) {
Accept();
}
if (ev.lNetworkEvents & FD_READ) {
if (reads_paused_) {
has_pending_reads_ = true;
} else {
Read();
}
}
if (ev.lNetworkEvents & FD_CLOSE) {
Close();
}
}
#elif defined(__LB_SHELL__) && !defined(__LB_ANDROID__)
// MessageLoop watcher callback.
void StreamListenSocket::OnObjectSignaled(int object) {
// Object Watcher removes the object whenever it gets signaled, so rewatch it
watcher_.StartWatching(object, base::MessagePumpShell::WATCH_READ, this);
switch (wait_state_) {
case WAITING_ACCEPT:
Accept();
break;
case WAITING_READ:
if (reads_paused_) {
has_pending_reads_ = true;
} else {
Read();
}
break;
default:
// Close() is called by Read() in the Linux case.
NOTREACHED();
break;
}
}
#elif defined(OS_STARBOARD)
void StreamListenSocket::OnSocketReadyToRead(SbSocket socket) {
switch (wait_state_) {
case WAITING_ACCEPT:
Accept();
break;
case WAITING_READ:
if (reads_paused_) {
has_pending_reads_ = true;
} else {
Read();
}
break;
default:
NOTREACHED();
break;
}
}
void StreamListenSocket::OnSocketReadyToWrite(SbSocket socket) {
// SbSocketWaiter callback, we don't listen for write events so we shouldn't
// ever reach here.
NOTREACHED();
}
#elif defined(OS_POSIX)
void StreamListenSocket::OnFileCanReadWithoutBlocking(int fd) {
switch (wait_state_) {
case WAITING_ACCEPT:
Accept();
break;
case WAITING_READ:
if (reads_paused_) {
has_pending_reads_ = true;
} else {
Read();
}
break;
default:
// Close() is called by Read() in the Linux case.
NOTREACHED();
break;
}
}
void StreamListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
// MessagePumpLibevent callback, we don't listen for write events
// so we shouldn't ever reach here.
NOTREACHED();
}
#endif
void StreamListenSocket::PauseReads() {
DCHECK(!reads_paused_);
reads_paused_ = true;
}
void StreamListenSocket::ResumeReads() {
DCHECK(reads_paused_);
reads_paused_ = false;
if (has_pending_reads_) {
has_pending_reads_ = false;
Read();
}
}
} // namespace net