[Libwebsockets] Synchronous API wrapping libwebsockets?

Andy Green andy at warmcat.com
Sun Nov 9 06:15:41 CET 2014



On 9 November 2014 13:00:48 GMT+08:00, Duy Lan Nguyen <ndlan2k at gmail.com> wrote:
>Some things I'm still not clear about:
>
>1.
>>case LWS_CALLBACK_CLIENT_WRITEABLE:
>>
>>- Throw the previous SendRequest.CompleteEvent, if there is any.
>>
>>- Call libwebsocket_write() to send current SendRequest.Data in the
>>queue,
>>if there is any.
>>
>>- Remove the current SendRequest in the queue to be the "previous"
>one.
>>
>>- Call libwebsocket_callback_on_writable()
>
>A> You would only do the last bit if there was more to send on that
>connection already.
>
>A> Otherwise you would just return 0 and let it go quiet there until
>the
>other thread saw something came for that connection to deal with.
>
>I need to notify the Send() call that libwebsocket_write() has
>completed
>successfully so that the Send() stops blocking and returns
>successfully.
>How do I know when libwebsocket_write() has completed successfully, to
>throw SendRequest.CompleteEvent for that Send()?

Depends what you mean by 'completed'... if you mean the work of the user code was finished, then it's enough when the libwebsocket_write returns for the last bit you were trying to send.

If you mean that the other side received it all, that's something completely different, the other side has to send something back to confirm.

lws might cache part of what you sent and require the socket to be writable more times before it is all sent.  That stuff is handled invisibly by the library, but to let it work you have to continuously be doing the service loop.

>A> You either have to deal with keeping your own list of active wsi, in
>order to have the right wsi for the data when you call
>libwebsocket_callback_on_writable(), or call ..._all_protocol() from
>the
>other thread if that is what your app is doing.
>
>A> You can hook ESTABLISHED and CLOSE callbacks to maintain your own
>wsi
>list if that's what you need.
>
>I thought there is only 1 wsi returned from
>libwebsocket_client_connect()
>(just called once in Connect()) to pass around. Could you please
>explain
>this a bit?

Even if you only have the one wsi, you still have races where 

 - the connection or ws handshake did not complete yet -- the wsi is live but not usable

 - the library decides to close and free your client connection, but the other thread continues to hold the now-dead wsi pointer

So you still need to handle CLIENT_ESTABLISHED and CLOSED callbacks to manage flagging the connection as usable by the other thread.

-Andy

>Many thanks,
>Lan
>
>
>
>
>On Sat, Nov 8, 2014 at 5:22 PM, Andy Green <andy at warmcat.com> wrote:
>
>>
>>
>> On 9 November 2014 07:55:07 GMT+08:00, Duy Lan Nguyen
><ndlan2k at gmail.com>
>> wrote:
>> >Hello,
>> >
>> >Appreciate if you could help. I'm trying to implement a simple
>> >Synchronous
>> >API wrapping libwebsockets (for client side, not server side),
>roughly
>> >as
>> >follows.
>> >
>> >MYSOCK = Connect(...);
>> >
>> >STATUS Send(MYSOCK, char* pbData, uint cbData, uint dwFlags);
>> >
>> >STATUS Receive(MYSOCK, char* pbData, uint cbData, uint dwFlags);
>> >
>> >
>> >Close(MYSOCK);
>>
>> Well, okay.  That's not the idea of lws I guess you already know.
>>
>> >DO YOU HAVE any ADVICE on HOW to do that most efficiently?
>> >
>> >
>> >
>> >I actually have the following design
>> >
>> >
>> >A global queue of RecvRequest struct
>> >
>> >A global queue of SendRequest struct
>> >
>> >
>> >Connect():
>> >
>> >Create a separate thread
>> >
>> >- calling libwebsocket_create_context()
>> >
>> >- calling libwebsocket_client_connect()
>> >
>> >- running the loop libwebsocket_service()
>>
>> OK.
>>
>> >Close():
>> >
>> >Just shutdown the above thread and callings properly
>> >
>> >
>> >Send():
>> >
>> >Add its SendRequest struct to the queue
>> >
>> >Call libwebsocket_callback_on_writable()
>> >
>> >Wait for its event SendRequest.CompleteEvent
>> >
>> >return STATUS
>> >
>> >
>> >Receive():
>> >
>> >Add its RecvRequest struct to the queue
>> >
>> >Wait for its event RecvRequest.CompleteEvent
>> >
>> >return STATUS
>> >
>> >
>> >CallBack():
>> >
>> >case LWS_CALLBACK_CLIENT_WRITEABLE:
>> >
>> >- Throw the previous SendRequest.CompleteEvent, if there is any.
>> >
>> >- Call libwebsocket_write() to send current SendRequest.Data in the
>> >queue,
>> >if there is any.
>> >
>> >- Remove the current SendRequest in the queue to be the "previous"
>one.
>> >
>> >- Call libwebsocket_callback_on_writable()
>>
>> You would only do the last bit if there was more to send on that
>> connection already.
>>
>> Otherwise you would just return 0 and let it go quiet there until the
>> other thread saw something came for that connection to deal with.
>>
>> >case LWS_CALLBACK_CLIENT_RECEIVE:
>> >
>> >- Pass received data to RecvRequest.Data in the queue, if there is
>any.
>> >
>> >- Remove the current RecvRequest in the queue.
>> >
>> >- Throw the its RecvRequest.CompleteEvent.
>> >
>> >
>> >
>> >DO YOU have any COMMENT on this design?
>>
>> You either have to deal with keeping your own list of active wsi, in
>order
>> to have the right wsi for the data when you call
>> libwebsocket_callback_on_writable(), or call ..._all_protocol() from
>the
>> other thread if that is what your app is doing.
>>
>> You can hook ESTABLISHED and CLOSE callbacks to maintain your own wsi
>list
>> if that's what you need.
>>
>> Basically your design should be OK for lws, you're only writing from
>the
>> service thread in the writable callback, and from the other thread
>you only
>> do the on_writable() call, these are the key things to get a good
>result if
>> there's more than one thread or process involved.
>>
>> -Andy
>>
>> >
>> >
>> >Many thanks,
>> >
>> >Lan
>> >
>> >
>>
>>------------------------------------------------------------------------
>> >
>> >_______________________________________________
>> >Libwebsockets mailing list
>> >Libwebsockets at ml.libwebsockets.org
>> >http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
>>
>>




More information about the Libwebsockets mailing list