I took the bitmask path for my implementation similar to what Daniel
has proposed.  I like the flexibility and clarity it offers.

Something like this might work (they need better names probably):

/* WS extension declarations as needed */
CURL_WS_COMPRESS    (1 << 10)

/* WS frame flags */
CURL_WS_FRAME_END   (1 << 9) /* An extension so that curl can inform the caller
                              * of curl_easy_ws_recv() that this is the end of
                              * the frame on the wire in case that is important
                              * to an extension. */
CURL_WS_FIN         (1 << 8)
CURL_WS_RSV1        (1 << 7)
CURL_WS_RSV2        (1 << 6)
CURL_WS_RSV3        (1 << 5)

/* Opcodes */
CURL_WS_OPCODE_0        0
CURL_WS_CONTINUATION    0
CURL_WS_OPCODE_1        1
CURL_WS_TEXT            1
CURL_WS_OPCODE_2        2
CURL_WS_BINARY          2
CURL_WS_OPCODE_3        3
CURL_WS_OPCODE_4        4
CURL_WS_OPCODE_5        5
CURL_WS_OPCODE_6        6
CURL_WS_OPCODE_7        7
CURL_WS_OPCODE_8        8
CURL_WS_CLOSE           8
CURL_WS_OPCODE_9        9
CURL_WS_PING            9
CURL_WS_OPCODE_A        10
CURL_WS_PONG            10
CURL_WS_OPCODE_B        11
CURL_WS_OPCODE_C        12
CURL_WS_OPCODE_D        13
CURL_WS_OPCODE_E        14
CURL_WS_OPCODE_F        15


CURLcode curl_easy_ws_send(CURL *curl, int flags, const void *data, size_t len);
CURLcode curl_easy_ws_recv(CURL *curl, int *flags, void *data, size_t
buflen, size_t *n);

/* Send a binary stream */
curl_easy_ws_send(easy, CURL_WS_BINARY, data, len);
curl_easy_ws_send(easy, CURL_WS_CONTINUATION, data, len);
curl_easy_ws_send(easy, CURL_WS_FIN | CURL_WS_CONTINUATION, data, len);

/* Send a close */
curl_easy_ws_send(easy, CURL_WS_FIN | CURL_WS_CLOSE, data, len);

/* Optional way libcurl could support for OPCODEs 8+ & libcurl asserts
the frame is CURL_WS_FIN)
curl_easy_ws_send(easy, CURL_WS_CLOSE, data, len);

/* Send a ping */
curl_easy_ws_send(easy, CURL_WS_FIN | CURL_WS_PING, data, len);

/* Receiving a binary frame with a buffer that is too small */
curl_easy_ws_recv(easy, &flags, data, buflen, &n);
returns: CURLE_AGAIN
flags: CURL_WS_BINARY

curl_easy_ws_recv(easy, &flags, data, buflen, &n);
returns: CURLE_AGAIN
flags: CURL_WS_FRAME_END | CURL_WS_BINARY
... the frame is complete now

libcurl should be able to do a bit of state checking in case the
caller makes a mistake, but it should only focus on the fragmentation
continuity and validating that a control message is not too long.  I
tend to think that libcurl should try to stay out of the business of
validating any of the payload formats because the rules for processing
are tied to frame type & extensions.

This extension concerns me as it renders the
curl_easy_ws_send()/recv() to not have value ... but as long as it
could be implemented using curl_easy_send()/recv() then I'm happy.
https://datatracker.ietf.org/doc/html/draft-ietf-hybi-websocket-multiplexing-11#section-8
tl;dr - they add a few bytes in front of the standard defined WS packet.

On Fri, Jul 2, 2021 at 6:42 AM Felipe Gasper <fel...@felipegasper.com> wrote:
>
>
>
> > On Jul 2, 2021, at 7:40 AM, Daniel Stenberg <dan...@haxx.se> wrote:
> >
> > On Fri, 2 Jul 2021, Felipe Gasper wrote:
> >
> > Thanks!
> >
> >> The send interface could look much like curl_easy_send():
> >>
> >> curl_ws_send( easy, buffer, buflen, &sent, enum curl_ws_message_type type, 
> >> enum curl_ws_flags flags )
> >
> > Or perhaps with the type and flags just made as a single bitmask.
>
> This will make it impossible to specify a continuation frame rather than a 
> data frame. (Context: when a message is fragmented, the message’s first frame 
> is text/binary, and the latter ones are continuation.)
>
> That may be OK if curl will commit to abstracting that distinction away.
>
> Also, if WS were to add a 3rd data type -- e.g., via some extension -- then 
> it would be possible to specify CURL_WS_TEXT | CURL_WS_FANCY_NEW_EXT_TYPE, 
> which means curl would need to detect that.
>
> Alternatively, have separate curl_ws_send_text and curl_ws_send_binary 
> functions?
>
> >
> >> Most WS libraries that I’ve seen implement reception as a callback, with a 
> >> separate control to pause reception of incoming messages.
> >
> > I won't say that's wrong, but I don't see how a callback helps with this 
> > API.
> >
> > curl_ws_recv() could just be made to not return until the entire packet can 
> > be returned. Or with an option to return a partial one.
>
> I assume you mean something like EAGAIN rather than actually blocking?
>
> Having the caller call curl_ws_recv() directly would mean that that same 
> caller would need to know when the socket has data to read. I don’t know if 
> that’s always a safe assumption.
>
> Also, WS includes ping/pong, so even if the socket has data there might not 
> be any application-level data incoming. (Ping/pong isn’t usually exposed to 
> the application.)
>
> > An area for consideration is how to deal with the buffer (size). I mean, if 
> > it wants to wait for a full packet to arrive I suppose it can be large and 
> > it might not fit in the user-provided buffer, so the application would need 
> > to call it multiple times do drain the data.
>
> Would this argue in favour of a callback, then? Curl could just allocate as 
> it knows it needs. The caller, then, could either memcpy or assume ownership 
> of the buffer (by, e.g., returning CURL_WS_NOFREE from the callback).
>
> Alternatively, there is precedent here with SOCK_SEQPACKET sockets, though 
> curl has the ability to deliver what IMO would be a smoother interface.
>
> >
> > I took the liberty of jotting down some of these API thoughts in the wiki 
> > page. Still incomplete and not really functional, but I figured it could 
> > help to stir up our collective minds..
> >
> >  https://github.com/curl/curl/wiki/WebSockets#api
>
> I feel funny asking this, but is there a comment feature in this wiki system? 
> I don’t see such, but it would seem useful.
>
> -FG

-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:   https://curl.se/mail/etiquette.html

Reply via email to