unix: handle MSG_PEEK on receive.
fix #18653 Change-Id: Ideaba943644481ffd6cf3e1801069508b7362c9a Reviewed-on: https://review.haiku-os.org/c/haiku/+/9860 Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
@@ -327,7 +327,7 @@ UnixDatagramEndpoint::Receive(const iovec* vecs, size_t vecCount,
|
|||||||
TRACE("[%" B_PRId32 "] %p->UnixDatagramEndpoint::Receive()\n",
|
TRACE("[%" B_PRId32 "] %p->UnixDatagramEndpoint::Receive()\n",
|
||||||
find_thread(NULL), this);
|
find_thread(NULL), this);
|
||||||
|
|
||||||
if ((flags & ~(MSG_DONTWAIT)) != 0)
|
if ((flags & ~(MSG_DONTWAIT | MSG_PEEK)) != 0)
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
|
|
||||||
bigtime_t timeout = 0;
|
bigtime_t timeout = 0;
|
||||||
@@ -370,7 +370,8 @@ UnixDatagramEndpoint::Receive(const iovec* vecs, size_t vecCount,
|
|||||||
|
|
||||||
struct sockaddr_storage addressStorage;
|
struct sockaddr_storage addressStorage;
|
||||||
|
|
||||||
ssize_t result = fifo->Read(vecs, vecCount, _ancillaryData, &addressStorage, timeout);
|
ssize_t result = fifo->Read(vecs, vecCount, _ancillaryData, &addressStorage, timeout,
|
||||||
|
(flags & MSG_PEEK) != 0);
|
||||||
|
|
||||||
// Notify select()ing writers, if we successfully read anything.
|
// Notify select()ing writers, if we successfully read anything.
|
||||||
size_t writable = fifo->Writable();
|
size_t writable = fifo->Writable();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
UnixRequest::UnixRequest(const iovec* vecs, size_t count,
|
UnixRequest::UnixRequest(const iovec* vecs, size_t count,
|
||||||
ancillary_data_container* ancillaryData,
|
ancillary_data_container* ancillaryData,
|
||||||
struct sockaddr_storage* address)
|
struct sockaddr_storage* address, bool clone)
|
||||||
:
|
:
|
||||||
fVecs(vecs),
|
fVecs(vecs),
|
||||||
fVecCount(count),
|
fVecCount(count),
|
||||||
@@ -34,7 +34,8 @@ UnixRequest::UnixRequest(const iovec* vecs, size_t count,
|
|||||||
fBytesTransferred(0),
|
fBytesTransferred(0),
|
||||||
fVecIndex(0),
|
fVecIndex(0),
|
||||||
fVecOffset(0),
|
fVecOffset(0),
|
||||||
fAddress(address)
|
fAddress(address),
|
||||||
|
fClone(clone)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < fVecCount; i++)
|
for (size_t i = 0; i < fVecCount; i++)
|
||||||
fTotalSize += fVecs[i].iov_len;
|
fTotalSize += fVecs[i].iov_len;
|
||||||
@@ -94,6 +95,19 @@ UnixRequest::AddAncillaryData(ancillary_data_container* data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
UnixRequest::CloneAncillaryData(ancillary_data_container* data)
|
||||||
|
{
|
||||||
|
if (fAncillaryData == NULL) {
|
||||||
|
fAncillaryData = gStackModule->create_ancillary_data_container();
|
||||||
|
if (fAncillaryData == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gStackModule->clone_ancillary_data(data, fAncillaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - UnixBufferQueue
|
// #pragma mark - UnixBufferQueue
|
||||||
|
|
||||||
|
|
||||||
@@ -147,6 +161,7 @@ UnixBufferQueue::Read(UnixRequest& request)
|
|||||||
bool user = gStackModule->is_syscall();
|
bool user = gStackModule->is_syscall();
|
||||||
|
|
||||||
size_t readable = Readable();
|
size_t readable = Readable();
|
||||||
|
const bool clone = request.IsClone();
|
||||||
void* data;
|
void* data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
@@ -168,19 +183,31 @@ UnixBufferQueue::Read(UnixRequest& request)
|
|||||||
size = readable;
|
size = readable;
|
||||||
|
|
||||||
ssize_t bytesRead;
|
ssize_t bytesRead;
|
||||||
if (user)
|
if (user) {
|
||||||
bytesRead = ring_buffer_user_read(fBuffer, (uint8*)data, size);
|
if (clone) {
|
||||||
else
|
bytesRead = ring_buffer_user_peek(fBuffer, request.BytesTransferred(),
|
||||||
bytesRead = ring_buffer_read(fBuffer, (uint8*)data, size);
|
(uint8*)data, size);
|
||||||
|
} else {
|
||||||
|
bytesRead = ring_buffer_user_read(fBuffer, (uint8*)data, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (clone) {
|
||||||
|
bytesRead = ring_buffer_peek(fBuffer, request.BytesTransferred(),
|
||||||
|
(uint8*)data, size);
|
||||||
|
} else {
|
||||||
|
bytesRead = ring_buffer_read(fBuffer, (uint8*)data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (bytesRead < 0)
|
if (bytesRead < 0)
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
if (bytesRead == 0)
|
if (bytesRead == 0)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
// Adjust ancillary data entry offsets, respectively attach the ones
|
if (clone) {
|
||||||
// that belong to the read data to the request.
|
// Clone ancillary data afterwards
|
||||||
if (AncillaryDataEntry* entry = fAncillaryData.Head()) {
|
} else if (AncillaryDataEntry* entry = fAncillaryData.Head()) {
|
||||||
|
// Adjust ancillary data entry offsets, respectively attach the ones
|
||||||
|
// that belong to the read data to the request.
|
||||||
size_t offsetDelta = bytesRead;
|
size_t offsetDelta = bytesRead;
|
||||||
while (entry != NULL && offsetDelta > entry->offset) {
|
while (entry != NULL && offsetDelta > entry->offset) {
|
||||||
// entry data have been read -- add ancillary data to request
|
// entry data have been read -- add ancillary data to request
|
||||||
@@ -200,7 +227,7 @@ UnixBufferQueue::Read(UnixRequest& request)
|
|||||||
readable -= bytesRead;
|
readable -= bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fType == UnixFifoType::Datagram) {
|
if (!clone && fType == UnixFifoType::Datagram) {
|
||||||
fDatagrams.RemoveHead();
|
fDatagrams.RemoveHead();
|
||||||
|
|
||||||
if (request.Address() != NULL)
|
if (request.Address() != NULL)
|
||||||
@@ -228,6 +255,18 @@ UnixBufferQueue::Read(UnixRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clone) {
|
||||||
|
AncillaryDataEntry* entry = fAncillaryData.Head();
|
||||||
|
size_t offsetDelta = request.BytesTransferred();
|
||||||
|
while (entry != NULL && offsetDelta > entry->offset) {
|
||||||
|
request.CloneAncillaryData(entry->data);
|
||||||
|
entry = fAncillaryData.GetNext(entry);
|
||||||
|
}
|
||||||
|
if (fType == UnixFifoType::Datagram && request.Address() != NULL)
|
||||||
|
memcpy(request.Address(), &datagramEntry->address, sizeof(datagramEntry->address));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,15 +428,15 @@ UnixFifo::Shutdown(uint32 shutdown)
|
|||||||
ssize_t
|
ssize_t
|
||||||
UnixFifo::Read(const iovec* vecs, size_t vecCount,
|
UnixFifo::Read(const iovec* vecs, size_t vecCount,
|
||||||
ancillary_data_container** _ancillaryData,
|
ancillary_data_container** _ancillaryData,
|
||||||
struct sockaddr_storage* address, bigtime_t timeout)
|
struct sockaddr_storage* address, bigtime_t timeout, bool peek)
|
||||||
{
|
{
|
||||||
TRACE("[%" B_PRId32 "] %p->UnixFifo::Read(%p, %ld, %" B_PRIdBIGTIME ")\n",
|
TRACE("[%" B_PRId32 "] %p->UnixFifo::Read(%p, %ld, %" B_PRIdBIGTIME ") %d\n",
|
||||||
find_thread(NULL), this, vecs, vecCount, timeout);
|
find_thread(NULL), this, vecs, vecCount, timeout, peek);
|
||||||
|
|
||||||
if (IsReadShutdown() && fBuffer.Readable() == 0)
|
if (IsReadShutdown() && fBuffer.Readable() == 0)
|
||||||
RETURN_ERROR(UNIX_FIFO_SHUTDOWN);
|
RETURN_ERROR(UNIX_FIFO_SHUTDOWN);
|
||||||
|
|
||||||
UnixRequest request(vecs, vecCount, NULL, address);
|
UnixRequest request(vecs, vecCount, NULL, address, peek);
|
||||||
fReaders.Add(&request);
|
fReaders.Add(&request);
|
||||||
fReadRequested += request.TotalSize();
|
fReadRequested += request.TotalSize();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class UnixRequest : public DoublyLinkedListLinkImpl<UnixRequest> {
|
|||||||
public:
|
public:
|
||||||
UnixRequest(const iovec* vecs, size_t count,
|
UnixRequest(const iovec* vecs, size_t count,
|
||||||
ancillary_data_container* ancillaryData,
|
ancillary_data_container* ancillaryData,
|
||||||
struct sockaddr_storage* address);
|
struct sockaddr_storage* address, bool clone = false);
|
||||||
|
|
||||||
off_t TotalSize() const { return fTotalSize; }
|
off_t TotalSize() const { return fTotalSize; }
|
||||||
off_t BytesTransferred() const { return fBytesTransferred; }
|
off_t BytesTransferred() const { return fBytesTransferred; }
|
||||||
@@ -48,9 +48,11 @@ public:
|
|||||||
|
|
||||||
ancillary_data_container* AncillaryData() const { return fAncillaryData; }
|
ancillary_data_container* AncillaryData() const { return fAncillaryData; }
|
||||||
void AddAncillaryData(ancillary_data_container* data);
|
void AddAncillaryData(ancillary_data_container* data);
|
||||||
|
status_t CloneAncillaryData(ancillary_data_container* data);
|
||||||
void UnsetAncillaryData();
|
void UnsetAncillaryData();
|
||||||
|
|
||||||
struct sockaddr_storage* Address() const { return fAddress; }
|
struct sockaddr_storage* Address() const { return fAddress; }
|
||||||
|
bool IsClone() const { return fClone; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const iovec* fVecs;
|
const iovec* fVecs;
|
||||||
@@ -61,6 +63,7 @@ private:
|
|||||||
size_t fVecIndex;
|
size_t fVecIndex;
|
||||||
size_t fVecOffset;
|
size_t fVecOffset;
|
||||||
struct sockaddr_storage* fAddress;
|
struct sockaddr_storage* fAddress;
|
||||||
|
bool fClone;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -134,7 +137,7 @@ public:
|
|||||||
|
|
||||||
ssize_t Read(const iovec* vecs, size_t vecCount,
|
ssize_t Read(const iovec* vecs, size_t vecCount,
|
||||||
ancillary_data_container** _ancillaryData,
|
ancillary_data_container** _ancillaryData,
|
||||||
struct sockaddr_storage* address, bigtime_t timeout);
|
struct sockaddr_storage* address, bigtime_t timeout, bool peek);
|
||||||
ssize_t Write(const iovec* vecs, size_t vecCount,
|
ssize_t Write(const iovec* vecs, size_t vecCount,
|
||||||
ancillary_data_container* ancillaryData,
|
ancillary_data_container* ancillaryData,
|
||||||
const struct sockaddr_storage* address, bigtime_t timeout);
|
const struct sockaddr_storage* address, bigtime_t timeout);
|
||||||
|
|||||||
@@ -483,7 +483,7 @@ UnixStreamEndpoint::Receive(const iovec* vecs, size_t vecCount,
|
|||||||
find_thread(NULL), this, vecs, vecCount);
|
find_thread(NULL), this, vecs, vecCount);
|
||||||
|
|
||||||
// TODO: handle MSG_WAITALL
|
// TODO: handle MSG_WAITALL
|
||||||
if ((flags & ~(MSG_DONTWAIT | MSG_WAITALL)) != 0)
|
if ((flags & ~(MSG_DONTWAIT | MSG_PEEK | MSG_WAITALL)) != 0)
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
|
|
||||||
bigtime_t timeout = 0;
|
bigtime_t timeout = 0;
|
||||||
@@ -521,7 +521,8 @@ UnixStreamEndpoint::Receive(const iovec* vecs, size_t vecCount,
|
|||||||
// unlock endpoint
|
// unlock endpoint
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
ssize_t result = fifo->Read(vecs, vecCount, _ancillaryData, NULL, timeout);
|
ssize_t result = fifo->Read(vecs, vecCount, _ancillaryData, NULL, timeout,
|
||||||
|
(flags & MSG_PEEK) != 0);
|
||||||
|
|
||||||
// Notify select()ing writers, if we successfully read anything.
|
// Notify select()ing writers, if we successfully read anything.
|
||||||
size_t writable = fifo->Writable();
|
size_t writable = fifo->Writable();
|
||||||
|
|||||||
@@ -60,6 +60,21 @@ destroy_scm_rights_descriptors(const ancillary_data_header* header,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
clone_scm_rights_descriptors(const ancillary_data_header* header, void* data)
|
||||||
|
{
|
||||||
|
int count = header->len / sizeof(file_descriptor*);
|
||||||
|
file_descriptor** descriptors = (file_descriptor**)data;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (descriptors[i] != NULL) {
|
||||||
|
inc_fd_ref_count(descriptors[i]);
|
||||||
|
inc_fd_open_count(descriptors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -334,7 +349,7 @@ unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container,
|
|||||||
"container\n", find_thread(NULL), count);
|
"container\n", find_thread(NULL), count);
|
||||||
|
|
||||||
error = gStackModule->add_ancillary_data(container, &header,
|
error = gStackModule->add_ancillary_data(container, &header,
|
||||||
descriptors, destroy_scm_rights_descriptors, NULL, NULL);
|
descriptors, destroy_scm_rights_descriptors, clone_scm_rights_descriptors, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup on error
|
// cleanup on error
|
||||||
|
|||||||
Reference in New Issue
Block a user