Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

socket.read($bytes) - "returns $bytes bytes" vs "returns UP TO $bytes bytes" #909

Closed
rurban opened this Issue · 3 comments

3 participants

@rurban
Collaborator

Lots of rakudo modules broke with io_cleanup1 socket changes:
perl6/specs#26

There was socket behavior change between Rakudo 2012.11 and 2012.12.

Previously .read(2048) returned 2048 bytes if available, currently it returns 512 (one chunk).
If chunk is smaller than $limit - for example .read(2) - then previous and current version returns 2 bytes.

So param changed its meaning from "desired amount of bytes" to "no more than bytes". That led to discussion about which one is correct.

Spec says
Reads and returns $bytes bytes from the handle

perl6 IRC discussion disagrees
bbkr: you're supposed to keep calling .read until either it returns zero or you have all the bytes
sorear, what is the point of length argument then?
bbkr: 256 seems a little buggy but in general, packet size limits will prevent you from getting all the data at once, and Berkeley sockets systems will return partial data rather than wait for future packets
bbkr: allows you to set an upper limit on the amount to read
...
so is it spec bug (the param means upper limit), or rakudo bug ?
bbkr: my hubris is telling me the spec is wrong and sockets should always follow a Berkeley-esque interface

@Whiteknight Whiteknight was assigned
@leto
Owner

@rurban do you have the tuits to write a test for this?

Unless I hear otherwise from core Rakudo devs, I will assume they want the original behavior, since they inherited this change from an unintended Parrot change.

@Whiteknight just to verify, was this an unintended change due to the refactor, or was this a conscious change of behavior?

@rurban
Collaborator

http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html
If fildes refers to a socket, read() shall be equivalent to recv() with no flags set.

The POSIX spec say that the $bytes parameter to socket.read contains the max buffer size to be returned, and the actual read buffer size is returned.

But there is an option to specify the behavior we had before:
"The receive low-water mark (the SO_RCVLOWAT setsockopt option) determines the minimum amount of data that must be received before the read function is completed. If the read function times out, any data that was received is returned to the application even if the amount of data received is less than the receive low-water mark value."

I suggest we keep our new implementation which matches the C specs (and perl5 IO::Socket).
The user should not be able to come up with an artifical socket buffer size, and force the library to follow that size.

#include  <sys/socket.h>
int       read(int s,
               char *buf,
               int len);
s   The socket descriptor.
buf Pointer to the buffer that receives the data.
len  Length, in bytes, of the buffer pointed to by the buf parameter. The maximum amount of data that can be received is 65535 bytes.

So we need to change our docs.

Problem is that we have a low-level API method socket.recv() which does it like POSIX, and a high-level API
method read() which docs said to always return the wanted number of bytes.

METHOD read(INTVAL bytes)

Read the given number of bytes from the socket and return them in a string.

Implemented by the same function Parrot_io_read_s(), which does the wanted high-level buffering already.

@bbkr bbkr referenced this issue in supernovus/perl6-http-easy
Closed

Invalid operation on binary string #6

@rurban rurban referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
@rurban rurban referenced this issue from a commit
@rurban rurban [spec] GH #909 Update the socket doc for read and recv for our new PO…
…SIX behaviour

Before parrot-4.10 the high-level read() returned the wanted amount of bytes.
Now it behaves the same as recv(), which means that up to bytes are returned

We might want to add a setsockopt(level, option, value) method.
7f5d727
@rurban rurban referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
@rurban rurban referenced this issue from a commit
@rurban rurban [GH #909] Add test for chunked socket read
Socket.read will return chunked parts.
2734bd2
@rurban rurban referenced this issue from a commit
@rurban rurban [GH #909] Add SO_ and SOL_ definitions, add setsocktopt test
Do not use the g/set_flags vtable interface for g/setsocktopt methods.
Be explicit as it is for sockets only.
3f17b60
@rurban rurban referenced this issue from a commit
@rurban rurban [spec] GH #909 Update the socket doc for read and recv for our new PO…
…SIX behaviour

Before parrot-4.10 the high-level read() returned the wanted amount of bytes.
Now it behaves the same as recv(), which means that up to bytes are returned

We might want to add a setsockopt(level, option, value) method.
e5378bf
@rurban rurban referenced this issue from a commit
@rurban rurban [GH #909] Add test for chunked socket read
Socket.read will return chunked parts.
2da776e
@rurban
Collaborator

Fixed our docs. Added api.yaml entry.

rakudo also fixed their implementation of IO::Socket. rakudo/rakudo@d2d2c85

There are two pending branches, which I try out:
rurban/socket-read2-gh909 (setsockopt on every overlarge read, send) and rurban/sockopt-gh909 (provide opt methods)

@rurban rurban closed this
@rurban rurban referenced this issue from a commit
@rurban rurban [GH #909] Add SO_ and SOL_ definitions, add setsocktopt test
Do not use the g/set_flags vtable interface for g/setsocktopt methods.
Be explicit as it is for sockets only.
bed0d3a
@Whiteknight Whiteknight removed their assignment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.