I built a single thread http server using lws on embedded linux. When a request is received, while previous one is being processed, it starts processing the second one BEFORE the first is finished.
Here are the logs while handling simple GET: Test client (5 requests/threads at one time):
Thread Thread Thread 140539624781568140539641566976 started 140539633174272 started started
Thread 140539517204224 started
Thread 140539616388864 started
Thread 140539624781568 finished
Thread 140539641566976 finished
Thread 140539633174272 finished
Thread 140539616388864 finished
Thread 140539517204224 finished
1. CURL code: 0 HTTP code: -1 str:
2. CURL code: 0 HTTP code: -1 str:
3. CURL code: 0 HTTP code: 200 str: {"status": true}
4. CURL code: 0 HTTP code: -1 str:
5. CURL code: 0 HTTP code: 200 str: {"status": true}
Server
my-http[5681]: lws: lws_http_action: (null), checking access rights for mask 0x0 - l.160. lwsLogger()
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: lws: lws_http_action: (null), checking access rights for mask 0x0 - l.160. lwsLogger()
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: lws: lws_http_action: (null), checking access rights for mask 0x0 - l.160. lwsLogger()
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: lws: lws_http_action: (null), checking access rights for mask 0x0 - l.160. lwsLogger()
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: - l.93. callback_dynamic_http_HTTP_WRITEABLE()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93. callback_dynamic_http_HTTP_WRITEABLE()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93. callback_dynamic_http_HTTP_WRITEABLE()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93. callback_dynamic_http_HTTP_WRITEABLE()
my-http[5681]: lws: lws_http_action: (null), checking access rights for mask 0x0 - l.160. lwsLogger()
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93. callback_dynamic_http_HTTP_WRITEABLE()
As you see, the order is pretty random, while the demanded one would be:
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93.
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93.
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93.
my-http[5681]: REST LWS_CALLBACK_HTTP - l.89. callback()
my-http[5681]: LWS_CALLBACK SEND - l.33. callback_dynamic_http_action()
my-http[5681]: REST LWS_CALLBACK_HTTP_WRITEABLE - l.94. callback()
my-http[5681]: TO BE SENT: {"status": true} - l.93.
So I am looking for some kind of solution implementing a queue of requests to be handled in a sequence, and a mechanism that will prevent from handling a request before the previous one is finished.
Is there a solution provided by lws?
Thanks!
Ok, after some examining I found a solution.
First I confirmed that server is single-threaded state machine, blocking it during request processing (
std::this_thread_sleep()
) and called next request - it was processed after sleep was finished.Inside our
int callback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
we have toMy problem was that, I assumed that requests are queued in the layer above the callback func and they are processed synchrously - ONE AT TIME, so I was setting pointer to statically allocated global variable...
So it should look like this (just an idea example, without any error checks)
Such code will deliver proper connection/request object to demanded context.
Instead of manually mallocing, u can use some more complex data structure like circular buffer or even the
std::list<T>
(it mustnt be continous dynamic memory container likestd::vector<T>
!) which is what I did. Smart pointers are not welcomed though.Cheers!