warmcat / libwebsockets

canonical libwebsockets.org networking library

Home Page:https://libwebsockets.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problem about integrating libwebsockets with existing application using socket file descriptor adoption

gmfcd128 opened this issue · comments

I am currently adapting libwebsocket to an existing application, one that starts its own webserver by accepting socket(), peek the input data from accepted socket, and maybe pass the socket file descriptor based on certain conditions, or do normal HTTP.(this part had beed replicated by using libwebsockets dynamic http callback).
I am thinking of passing the accepted socket into libwebsocket by lws_adopt_descriptor_vhost, but the accept() seems to block the whole loop
I want to get some more info on how to implement the event loop, if this is even possible.

IIUI, redhat used lws for something similar a few years ago, lws supports the peeking and accepted socket handoff (after some work at the time, since this was not what I was originally imagining). As you say though this is as much an event loop issue as it is managing the data flow or sharing the socket, finding a way to hand off event monitoring on the fd between the two codebases.

What's the existing app's event wait for the accepted fd? If you can't share the wait, it will end up with 'an app thread' and 'an lws thread' which will complicate any other integration.

The most flexible and modern way in lws to cope with wait sharing is 'custom event lib', you can see a worked http server example here

https://github.com/warmcat/libwebsockets/blob/main/minimal-examples-lowlevel/http-server/minimal-http-server-eventlib-custom/minimal-http-server.c

Basically you roll your own (inline with the code) sparse event lib implementation that wires up to whatever junk you have in the old app (in the example, demonstrated by poll() based wait done by hand), but presents to lws as a modern eventlib support api struct. Have a look and see if it can help in your case.

to be more accurate, the old application doesn't seems to have have event loop at all
the abbreviated code is:
// single server thread entry function
void HttpServerDaemon()
{
// variables, socket create, listen etc.
......
while(1)
{
//select() on master socket
num = select(MAX_FD_NUM, &read_set, NULL, NULL, &sertime);
if (num == SOCKERR)
continue;
......
tmp_sock = accept(tmpFd, /IP_NULL/ (struct sockaddr )tmpClientSockAdd, /IP_NULL/ &len);
if (tmp_sock == INVALID_SOCKET)
continue;
else
// do stuff
......
if (xTempInfo.ssl != NULL || select(MAX_FD_NUM, &readFds, NULL, NULL, &timeout) == 1)
{
char tmpBuf[30] = {0};
if (ifSslFlg == 0)
tmpRecvLen = recv(tmp_sock, IppWsdPeekBuf, HS_IPP_WSD_PEEK_SIZE, MSG_PEEK); /
MSG_PEEK = 2, => return data without removing from socket */
else
{
tmpRecvLen = SSL_read(xTempInfo.ssl, xTempInfo.ssl1stPkt, sizeof(xTempInfo.ssl1stPkt));
if (tmpRecvLen == 1) // workaround for AES 3DES, only read 1 byte in first time even there are many data
{
tmpRecvLen = SSL_read(xTempInfo.ssl, xTempInfo.ssl1stPkt + 1, sizeof(xTempInfo.ssl1stPkt) - tmpRecvLen);
if (tmpRecvLen >= 0)
{
tmpRecvLen += 1;
}
else
tmpRecvLen = 1;
......
// if condition is true, hand off the accepted socket FD as parameter to specific function
// else: call another function(that parses the read buffer and send HTTP response)

}

}

My major concern of the previous question is that I want to find a efficient method that put the workflow into libwebsockets, whether pass the file descriptor into LWS after make sure the socket can be served normal HTTP, or fiddle with libwebsockets to give up the file descriptor when peeked specific data.
All the steps mentioned above, and the function that gets called to service the request are simple blocking system calls, and the socket when arrived at lws_event_loop_ops.sock_accept seems to become non-blocking, I don't know if putting those code in LWS will cause any potential problem

Is it worth caring about the old implementation? You can just use the minimal http server example to replace this if that's all there is to it and use lws default event loop to manage everything.

If there are virtual pages generated in the old code, you could modify these to generate data at WRITEABLE callback time still all sent by lws.

It doesn't look like what's there before is worth the respect of trying to work with it.

thanks for the explanation, after combining the current logic with the minimal-http server-example(logic in custom_poll_run and dynamic HTTP callback function) the code seems to work as expected...