Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /base /sync_socket_posix.cc
blob: 052aed5b4b46cd999cd727b60997c73753440a49 [file] [log] [blame] [edit]
// Copyright 2012 The Chromium Authors
// 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<errno.h>
#include<fcntl.h>
#include<limits.h>
#include<poll.h>
#include<stddef.h>
#include<stdio.h>
#include<sys/ioctl.h>
#include<sys/socket.h>
#include<sys/types.h>
#include"base/check_op.h"
#include"base/containers/span.h"
#include"base/files/file_util.h"
#include"base/numerics/safe_conversions.h"
#include"base/threading/scoped_blocking_call.h"
#include"build/build_config.h"
#if BUILDFLAG(IS_SOLARIS)
#include<sys/filio.h>
#endif
namespace base{
namespace{
// To avoid users sending negative message lengths to Send/Receive
// we clamp message lengths, which are size_t, to no more than INT_MAX.
constsize_t kMaxMessageLength=static_cast<size_t>(INT_MAX);
// Writes |length| of |buffer| into |handle|. Returns the number of bytes
// written or zero on error. |length| must be greater than 0.
size_tSendHelper(SyncSocket::Handle handle, span<constuint8_t> data){
CHECK_LE(data.size(), kMaxMessageLength);
DCHECK_NE(handle,SyncSocket::kInvalidHandle);
returnWriteFileDescriptor(handle, data)? data.size():0;
}
}// namespace
// static
boolSyncSocket::CreatePair(SyncSocket* socket_a,SyncSocket* socket_b){
DCHECK_NE(socket_a, socket_b);
DCHECK(!socket_a->IsValid());
DCHECK(!socket_b->IsValid());
#if BUILDFLAG(IS_APPLE)
int nosigpipe=1;
#endif// BUILDFLAG(IS_APPLE)
ScopedHandle handles[2];
{
Handle raw_handles[2]={kInvalidHandle, kInvalidHandle};
if(socketpair(AF_UNIX, SOCK_STREAM,0, raw_handles)!=0){
returnfalse;
}
handles[0].reset(raw_handles[0]);
handles[1].reset(raw_handles[1]);
}
#if BUILDFLAG(IS_APPLE)
// On OSX an attempt to read or write to a closed socket may generate a
// SIGPIPE rather than returning -1. setsockopt will shut this off.
if(0!= setsockopt(handles[0].get(), SOL_SOCKET, SO_NOSIGPIPE,&nosigpipe,
sizeof(nosigpipe))||
0!= setsockopt(handles[1].get(), SOL_SOCKET, SO_NOSIGPIPE,&nosigpipe,
sizeof(nosigpipe))){
returnfalse;
}
#endif
// Copy the handles out for successful return.
socket_a->handle_= std::move(handles[0]);
socket_b->handle_= std::move(handles[1]);
returntrue;
}
voidSyncSocket::Close(){
handle_.reset();
}
size_tSyncSocket::Send(span<constuint8_t> data){
ScopedBlockingCall scoped_blocking_call(FROM_HERE,BlockingType::MAY_BLOCK);
returnSendHelper(handle(), data);
}
size_tSyncSocket::Receive(span<uint8_t> buffer){
ScopedBlockingCall scoped_blocking_call(FROM_HERE,BlockingType::MAY_BLOCK);
CHECK_LE(buffer.size(), kMaxMessageLength);
DCHECK(IsValid());
if(ReadFromFD(handle(), as_writable_chars(buffer))){
return buffer.size();
}
return0;
}
size_tSyncSocket::ReceiveWithTimeout(span<uint8_t> buffer,TimeDelta timeout){
ScopedBlockingCall scoped_blocking_call(FROM_HERE,BlockingType::MAY_BLOCK);
CHECK_LE(buffer.size(), kMaxMessageLength);
DCHECK(IsValid());
// Only timeouts greater than zero and less than one second are allowed.
DCHECK_GT(timeout.InMicroseconds(),0);
DCHECK_LT(timeout.InMicroseconds(),Seconds(1).InMicroseconds());
// Track the start time so we can reduce the timeout as data is read.
TimeTicks start_time=TimeTicks::Now();
constTimeTicks finish_time= start_time+ timeout;
struct pollfd pollfd;
pollfd.fd= handle();
pollfd.events= POLLIN;
pollfd.revents=0;
size_t bytes_read_total=0;
while(!buffer.empty()){
constTimeDelta this_timeout= finish_time-TimeTicks::Now();
constint timeout_ms=
static_cast<int>(this_timeout.InMillisecondsRoundedUp());
if(timeout_ms<=0){
break;
}
constint poll_result= poll(&pollfd,1, timeout_ms);
// Handle EINTR manually since we need to update the timeout value.
if(poll_result==-1&& errno== EINTR){
continue;
}
// Return if other type of error or a timeout.
if(poll_result<=0){
return bytes_read_total;
}
// poll() only tells us that data is ready for reading, not how much. We
// must Peek() for the amount ready for reading to avoid blocking.
// At hang up (POLLHUP), the write end has been closed and there might still
// be data to be read.
// No special handling is needed for error (POLLERR); we can let any of the
// following operations fail and handle it there.
DCHECK(pollfd.revents&(POLLIN| POLLHUP| POLLERR))<< pollfd.revents;
constsize_t bytes_to_read= std::min(Peek(), buffer.size());
// There may be zero bytes to read if the socket at the other end closed.
if(!bytes_to_read){
return bytes_read_total;
}
constsize_t bytes_received=Receive(buffer.first(bytes_to_read));
bytes_read_total+= bytes_received;
buffer= buffer.subspan(bytes_received);
if(bytes_received!= bytes_to_read){
return bytes_read_total;
}
}
return bytes_read_total;
}
size_tSyncSocket::Peek(){
DCHECK(IsValid());
int number_chars=0;
if(ioctl(handle_.get(), FIONREAD,&number_chars)==-1){
// If there is an error in ioctl, signal that the channel would block.
return0;
}
return checked_cast<size_t>(number_chars);
}
boolSyncSocket::IsValid()const{
return handle_.is_valid();
}
SyncSocket::HandleSyncSocket::handle()const{
return handle_.get();
}
SyncSocket::HandleSyncSocket::Release(){
return handle_.release();
}
boolCancelableSyncSocket::Shutdown(){
DCHECK(IsValid());
return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR))>=0;
}
size_tCancelableSyncSocket::Send(span<constuint8_t> data){
CHECK_LE(data.size(), kMaxMessageLength);
DCHECK(IsValid());
constint flags= fcntl(handle(), F_GETFL);
if(flags!=-1&&(flags& O_NONBLOCK)==0){
// Set the socket to non-blocking mode for sending if its original mode
// is blocking.
fcntl(handle(), F_SETFL, flags| O_NONBLOCK);
}
constsize_t len=SendHelper(handle(), data);
if(flags!=-1&&(flags& O_NONBLOCK)==0){
// Restore the original flags.
fcntl(handle(), F_SETFL, flags);
}
return len;
}
// static
boolCancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
CancelableSyncSocket* socket_b){
returnSyncSocket::CreatePair(socket_a, socket_b);
}
}// namespace base

[8]ページ先頭

©2009-2025 Movatter.jp