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",
|
||||
find_thread(NULL), this);
|
||||
|
||||
if ((flags & ~(MSG_DONTWAIT)) != 0)
|
||||
if ((flags & ~(MSG_DONTWAIT | MSG_PEEK)) != 0)
|
||||
return EOPNOTSUPP;
|
||||
|
||||
bigtime_t timeout = 0;
|
||||
@@ -370,7 +370,8 @@ UnixDatagramEndpoint::Receive(const iovec* vecs, size_t vecCount,
|
||||
|
||||
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.
|
||||
size_t writable = fifo->Writable();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
UnixRequest::UnixRequest(const iovec* vecs, size_t count,
|
||||
ancillary_data_container* ancillaryData,
|
||||
struct sockaddr_storage* address)
|
||||
struct sockaddr_storage* address, bool clone)
|
||||
:
|
||||
fVecs(vecs),
|
||||
fVecCount(count),
|
||||
@@ -34,7 +34,8 @@ UnixRequest::UnixRequest(const iovec* vecs, size_t count,
|
||||
fBytesTransferred(0),
|
||||
fVecIndex(0),
|
||||
fVecOffset(0),
|
||||
fAddress(address)
|
||||
fAddress(address),
|
||||
fClone(clone)
|
||||
{
|
||||
for (size_t i = 0; i < fVecCount; i++)
|
||||
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
|
||||
|
||||
|
||||
@@ -147,6 +161,7 @@ UnixBufferQueue::Read(UnixRequest& request)
|
||||
bool user = gStackModule->is_syscall();
|
||||
|
||||
size_t readable = Readable();
|
||||
const bool clone = request.IsClone();
|
||||
void* data;
|
||||
size_t size;
|
||||
|
||||
@@ -168,19 +183,31 @@ UnixBufferQueue::Read(UnixRequest& request)
|
||||
size = readable;
|
||||
|
||||
ssize_t bytesRead;
|
||||
if (user)
|
||||
bytesRead = ring_buffer_user_read(fBuffer, (uint8*)data, size);
|
||||
else
|
||||
bytesRead = ring_buffer_read(fBuffer, (uint8*)data, size);
|
||||
|
||||
if (user) {
|
||||
if (clone) {
|
||||
bytesRead = ring_buffer_user_peek(fBuffer, request.BytesTransferred(),
|
||||
(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)
|
||||
return bytesRead;
|
||||
if (bytesRead == 0)
|
||||
return B_ERROR;
|
||||
|
||||
// Adjust ancillary data entry offsets, respectively attach the ones
|
||||
// that belong to the read data to the request.
|
||||
if (AncillaryDataEntry* entry = fAncillaryData.Head()) {
|
||||
if (clone) {
|
||||
// Clone ancillary data afterwards
|
||||
} 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;
|
||||
while (entry != NULL && offsetDelta > entry->offset) {
|
||||
// entry data have been read -- add ancillary data to request
|
||||
@@ -200,7 +227,7 @@ UnixBufferQueue::Read(UnixRequest& request)
|
||||
readable -= bytesRead;
|
||||
}
|
||||
|
||||
if (fType == UnixFifoType::Datagram) {
|
||||
if (!clone && fType == UnixFifoType::Datagram) {
|
||||
fDatagrams.RemoveHead();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -389,15 +428,15 @@ UnixFifo::Shutdown(uint32 shutdown)
|
||||
ssize_t
|
||||
UnixFifo::Read(const iovec* vecs, size_t vecCount,
|
||||
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",
|
||||
find_thread(NULL), this, vecs, vecCount, timeout);
|
||||
TRACE("[%" B_PRId32 "] %p->UnixFifo::Read(%p, %ld, %" B_PRIdBIGTIME ") %d\n",
|
||||
find_thread(NULL), this, vecs, vecCount, timeout, peek);
|
||||
|
||||
if (IsReadShutdown() && fBuffer.Readable() == 0)
|
||||
RETURN_ERROR(UNIX_FIFO_SHUTDOWN);
|
||||
|
||||
UnixRequest request(vecs, vecCount, NULL, address);
|
||||
UnixRequest request(vecs, vecCount, NULL, address, peek);
|
||||
fReaders.Add(&request);
|
||||
fReadRequested += request.TotalSize();
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class UnixRequest : public DoublyLinkedListLinkImpl<UnixRequest> {
|
||||
public:
|
||||
UnixRequest(const iovec* vecs, size_t count,
|
||||
ancillary_data_container* ancillaryData,
|
||||
struct sockaddr_storage* address);
|
||||
struct sockaddr_storage* address, bool clone = false);
|
||||
|
||||
off_t TotalSize() const { return fTotalSize; }
|
||||
off_t BytesTransferred() const { return fBytesTransferred; }
|
||||
@@ -48,9 +48,11 @@ public:
|
||||
|
||||
ancillary_data_container* AncillaryData() const { return fAncillaryData; }
|
||||
void AddAncillaryData(ancillary_data_container* data);
|
||||
status_t CloneAncillaryData(ancillary_data_container* data);
|
||||
void UnsetAncillaryData();
|
||||
|
||||
struct sockaddr_storage* Address() const { return fAddress; }
|
||||
bool IsClone() const { return fClone; }
|
||||
|
||||
private:
|
||||
const iovec* fVecs;
|
||||
@@ -61,6 +63,7 @@ private:
|
||||
size_t fVecIndex;
|
||||
size_t fVecOffset;
|
||||
struct sockaddr_storage* fAddress;
|
||||
bool fClone;
|
||||
};
|
||||
|
||||
|
||||
@@ -134,7 +137,7 @@ public:
|
||||
|
||||
ssize_t Read(const iovec* vecs, size_t vecCount,
|
||||
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,
|
||||
ancillary_data_container* ancillaryData,
|
||||
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);
|
||||
|
||||
// TODO: handle MSG_WAITALL
|
||||
if ((flags & ~(MSG_DONTWAIT | MSG_WAITALL)) != 0)
|
||||
if ((flags & ~(MSG_DONTWAIT | MSG_PEEK | MSG_WAITALL)) != 0)
|
||||
return EOPNOTSUPP;
|
||||
|
||||
bigtime_t timeout = 0;
|
||||
@@ -521,7 +521,8 @@ UnixStreamEndpoint::Receive(const iovec* vecs, size_t vecCount,
|
||||
// unlock endpoint
|
||||
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.
|
||||
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 -
|
||||
|
||||
|
||||
@@ -334,7 +349,7 @@ unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container,
|
||||
"container\n", find_thread(NULL), count);
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user