[Libwebsockets] Lws_service with specific socket

Andy Green andy at warmcat.com
Wed Dec 20 21:47:10 CET 2017



On December 21, 2017 12:50:43 AM GMT+09:00, "Théo BRIGNOL" <theo.brignol at imerir.com> wrote:
>Hello,
>
>First of all thanks for your answers.

I'm going to add back the list in the hope this may be useful to someone else.

>I worked with TcpSockets in c and I decided to integrate WebSockets in
>my
>system.
>
>To avoid multithreading my main program open a socket (*socket*()),
>*bind*
>it and *listen* on it. After that, I launched programs wich execute
>*accept*()
>on my main socket.
>I want to reproduce this performance with WebSocket in order to not
>change
>behavior.

Well lws broadly follows this, but not the "launching programs" bit.

>When I saw that "lws_create_context" function open a socket, bind it
>and
>listen on it I searched a solution in my sub-programs to execute a
>lws_service on the socket's file descriptor.
>
>But, "
>
>After calling, user code needs to take care
> of calling lws_service() with the context pointer to get the
> server's sockets serviced.  This must be done in the same process
> context as the initialization call. ".

Yes, but it's just normal.  Think about it, after fork() there are two different processes with their own mappings.  At creation, it happens their data memory starts off identical, but writes in one (eg, changing lws state) are not reflected in any other related process.

>Consequently, I'am searching a new solution. I'm trying to create as
>many
>virtualhosts as sub-programs I launched, sharing the same port and the
>same
>socket.

You do not need to do these vhosts.  At least you have not given any reason for it except "this is like what I did before".  But maybe what you did before also did not need to do this.

>For the moment I just have one protocol, and my callback function send
>string when I received data from a client.
>
>*When I connect more than one browser client, the data that the server
>send
>as a response of one client is received by all the connected clients.*
>
>I'm confusing and I don't see how to "separate" my client. I don't know
>if
>I'm clear or not...

This sounds more like a normal question.  You can select which wsi (ie, "connection") is targeted for a writable callback with lws_callback_on_writable(struct lws *wsi); or you can get everyone connected with that protocol to receive their own callback using lws_callback_on_writable_all_protocol() or another variant.  So the first part to handle this is only provoke the writable callback on the specific wsi that has something to write.

If you look at any of the example protocols, now provided in plugins, eg

https://github.com/warmcat/libwebsockets/blob/d2bc2d17043ff373c8f2c54cd3eff473078aa16f/plugins/protocol_dumb_increment.c#L31

you will see they define a struct that has an instance created for every connection.  They inform lws of the size of this struct in the protocols entry.

https://github.com/warmcat/libwebsockets/blob/d2bc2d17043ff373c8f2c54cd3eff473078aa16f/plugins/protocol_dumb_increment.c#L136

Lws auto-creates some initially zeroed storage sized from that for each accepted connection, and passes it into the callback in the user param for the wsi.  You can cast this

https://github.com/warmcat/libwebsockets/blob/d2bc2d17043ff373c8f2c54cd3eff473078aa16f/plugins/protocol_dumb_increment.c#L58

so now you have your own struct that you define, and a pointer (in the lws examples, it's always called 'pss') to an instance of it for each connection that got accepted.  In there, you store any state specific to that connection, so if there is some event for that connection, information about it is recorded in its pss.

So the second part to solve it is when you get a writable callback for a particular wsi, you should look in the pss struct bound to that wsi to find out what if anything needs writing for that guy.  In this way each connection gets to have its own private ideas about its situation.  For dumb increment case, the incrementing number it sends is stored in the pss.  That is why if you open a second browser instance on the test server, each connection gets its own number going up from zero unrelated to the number any other browser window is getting.

-Andy

>Thanks,
>
>Theo
>
>
>*P.S :* Sorry for my English which is very bad..
>
>
>
>
>2017-12-19 14:51 GMT+01:00 Andy Green <andy at warmcat.com>:
>
>>
>>
>> On December 19, 2017 10:21:06 PM GMT+09:00, Edwin van den Oetelaar <
>> oetelaar.automatisering at gmail.com> wrote:
>> >On Tue, Dec 19, 2017 at 2:08 PM, Théo BRIGNOL
><theo.brignol at imerir.com>
>> >wrote:
>> >
>> >> Ok sorry for my unclear explanation.
>> >>
>> >> Simply :
>> >>
>> >> I have a file descriptor of a socket which is open. I'd like to
>know
>> >if
>> >> it's possible to construct a context using this socket. And to
>start
>> >a
>> >> lws_service on it.
>> >>
>> >>
>> >If the socket is just a clean socket, no data has flowed through it
>> >(like a
>> >socket you get from accept() ) then you might be able to do it.
>> >(I have no example, but technically it should be possible to start
>data
>> >flow and handshaking on it)
>>
>> Lws does have "adopt" apis where it can take over responsibility for
>a
>> socket something else accepted.  It can even do that if the socket is
>> "dirty", ie accepted and read-from... you have to pass into the adopt
>api
>> whatever was read in that case.
>>
>> But there's no equivalent for adopting a listen socket.  Lws knows
>how to
>> create and configure a listen socket per vhost when the vhost is
>created,
>> so there is no point.  If that's what it's about it's dynamic vhost
>> creation, which lws supports... maybe that's why the EXPLICIT_VHOST
>flag
>> was mentioned before.
>>
>> Generally, magicking up random listen sockets isn't the right
>answer... a
>> listen socket usually implies some firewall or port-forward
>arrangements
>> supporting it.  There should be a way to do everything on one port;
>some
>> very complex websites manage with just :443.
>>
>> If the OP must have it for some reason, the key point is one context
>can
>> hold many vhosts, and each vhost can manage a listen socket at a
>specified
>> port.  But lws creates those listen sockets.  In the case more than
>one
>> vhost listens on the same port, SNI and / or the Host: header are
>used to
>> bind the incoming connection to the right vhost.
>>
>> -Andy
>>
>> >If the socket has been used for http/ws-protocol, like you suggested
>> >(because you want to start different sub-programs based on something
>> >that
>> >came through the socket) I think you will not succeed.
>> >
>> >Why not use the library as it was designed?
>> >Use a more distributed design, let the WS server take the
>network-calls
>> >and
>> >go from there.
>> >Take a look at loosly coupled services and more scalable designs.
>Look
>> >at
>> >ZeroMQ book for inspiration.
>> >
>> >good luck,
>> >Edwin
>> >
>> >
>> >>
>> >> Thanks,
>> >> Theo
>> >>
>> >>
>> >> 2017-12-19 12:04 GMT+01:00 Edwin van den Oetelaar <
>> >> oetelaar.automatisering at gmail.com>:
>> >>
>> >>>
>> >>>
>> >>> On Tue, Dec 19, 2017 at 11:42 AM, Théo BRIGNOL
>> ><theo.brignol at imerir.com>
>> >>> wrote:
>> >>>
>> >>>>
>> >>>> Hello,
>> >>>>
>> >>>> I have a question regarding a simple case.
>> >>>>
>> >>>> I want to create a main socket in my main program.
>> >>>> In order to do that, I create a main context with default
>protocols
>> >and
>> >>>> one specific listening port.
>> >>>>
>> >>>
>> >>> This I understand.
>> >>>
>> >>>
>> >>>>
>> >>>> This main program will launch as many as sub-programs that whe
>> >decided
>> >>>> with the function "execl".
>> >>>>
>> >>>
>> >>> This makes no sense to me, you want to replace the current
>process
>> >with
>> >>> another?
>> >>> You destroy all state in the orignal connection (WS state, it not
>> >just a
>> >>> file descriptor)
>> >>>
>> >>> ref : https://linux.die.net/man/3/execl
>> >>>
>> >>> The *exec*() family of functions replaces the current process
>image
>> >with
>> >>> a new process image.
>> >>>
>> >>>
>> >>>>
>> >>>> I want this sub-programs to redefine protocols, and accept
>> >connection on
>> >>>> the main port on the main socket (the "father" socket). Note
>that
>> >with
>> >>>> execl I can't pass main context as a parameter.
>> >>>>
>> >>>> The fact is that I tried many solutions without succes
>> >>>> (LWS_EXPLICIT_VHOST option, external poll fd, etc..).
>> >>>>
>> >>>> Have you any idea in order to do that ?
>> >>>>
>> >>>
>> >>> I have not a clue what you try to achieve here. Or why?
>> >>> Do you have any example where this approach is a good solution to
>a
>> >>> problem?
>> >>> I do not know everything, so I am willing to learn here.
>> >>>
>> >>>
>> >>>>
>> >>>> Thank you for your comprehension.
>> >>>>
>> >>>
>> >>> ;-) I am completely without comprehension ;-)
>> >>>
>> >>> Greetings,
>> >>> Edwin
>> >>>
>> >>>
>> >>>> Best Regards,
>> >>>>
>> >>>> Theo
>> >>>>
>> >>>> _______________________________________________
>> >>>> Libwebsockets mailing list
>> >>>> Libwebsockets at ml.libwebsockets.org
>> >>>> https://libwebsockets.org/mailman/listinfo/libwebsockets
>> >>>>
>> >>>>
>> >>>
>> >>
>> _______________________________________________
>> Libwebsockets mailing list
>> Libwebsockets at ml.libwebsockets.org
>> https://libwebsockets.org/mailman/listinfo/libwebsockets
>>



More information about the Libwebsockets mailing list