View Issue Details

IDProjectCategoryView StatusLast Update
0002984libmicrohttpdexternal APIpublic2013-08-13 14:36
Reporterbplant Assigned ToChristian Grothoff  
PrioritynormalSeverityfeatureReproducibilityalways
Status closedResolutionwon't fix 
Product Version0.9.27 
Target Version0.9.29Fixed in Version0.9.29 
Summary0002984: Can't queue connections when using MHD_add_connection
DescriptionIf a connection is attempted to be added using MHD_add_connection but daemon->max_connections <= 0, MHD_NO is returned. This would be ok, except that is no way to distinguish this from another failure in MHD_add_connection (such as a malloc failure for example).

Is it possible to change the return value when daemon->max_connections <= 0? My max connections is very low because I'm running on a microprocessor that only has a few hundred KB of RAM.
TagsNo tags attached.

Activities

Christian Grothoff

2013-08-10 20:32

manager   ~0007327

That cannot really be changed in a backwards-compatible fashion. However, we might be able to do something with 'errno'. I would suspect it is already set "correctly" for out-of-memory (ENOMEM), and we might set 'errno' to something like 'ENFILE' if we have too many connections. Would that do?

Christian Grothoff

2013-08-10 20:41

manager   ~0007328

Should be fixed in SVN 28486 (using errno).

bplant

2013-08-11 23:25

reporter   ~0007337

I don't think the socket should be closed (when using MHD_add_connection) before errno is set and MHD_NO is returned as this doesn't allow me to try adding the connection again (when hopefully some other connections have been processed and it gets accepted).

Christian Grothoff

2013-08-11 23:40

manager   ~0007341

If you really want to do that, you could 'dup' the socket first. I think the possibility of a socket leak because we return an error code and the client fails to check is too real to change this. Not to mention that we'd again run into the issue of not being backwards compatible, this time in a really bad way (sudden socket leak!). So really, if you need this, just 'dup' first, then you can close the duplicate FD later if the MHD_add_connection succeeded.

bplant

2013-08-12 00:03

reporter   ~0007342

Unfortunately the "operating system" (if you can really call it that) doesn't support dup().

I wouldn't have thought it would be too much of an issue if the socket wasn't closed ONLY when passed via MHD_add_connection. Yes, it would break backwards compatibility, but I'm probably the only person using this feature ;-)

Christian Grothoff

2013-08-12 00:42

manager   ~0007343

Sadly, you're mistaken: I know other projects that also _do_ use that API. And I'd _really_ dislike bloating the API with an 'add2' over this. The other option, adding another flag is also extremely ugly. Other ideas?

bplant

2013-08-12 11:18

reporter   ~0007345

Wow, I never thought anyone else would use this feature when I requested it 2 or so years back!

Unfortunately I cannot think of another way of doing it. In my mind, the "correct" way (if there is such a thing) is to not close the socket. Not because this is going to suit me/my project better, but because MHD isn't "responsible" for this socket. I.e. MHD didn't create the socket and therefore I don't think it should be allowed to close it. This is obviously in contrast to the sockets that MHD creates itself when a new request hits port 80 and thus *should* close. On the other hand; I really dislike changing APIs.

As for the 'add2' function and bloating, it wouldn't add too many bytes to the compiled code as there are only 2 lines of code in the current MHD_add_connection function. But I also dislike having multiple functions that do *almost* the same thing. Where does it end?

What to do, what to do......

Christian Grothoff

2013-08-12 11:23

manager   ~0007346

Also, each exported symbol increases code size and linking/loading costs. Now, I still think that if you give the socket to MHD, you give up control --- after all, depending on what happens MHD may close it anyway shortly thereafter. Here is another idea: what if we added a way for you to 'reserve' a certain number of connection slots for (external) "MHD_add_connection" operations? That way, you might be able to do counting (how many did YOU add before explicitly that were not yet finished) to pre-determine the outcome, despite "concurrent" accept operations going on.

bplant

2013-08-12 12:19

reporter   ~0007347

A very good point - the socket is also closed after a HTTP request is completed successfully. I guess the difference here though is that the request was completed successfully so there would never be any need to retry.

Not sure about the counting. I'd have to use a callback when the request is completed, but how would I distinguish between normal connections and those that I add using MHD_add_connection? My connection limit is currently set to 5. If I increase it to 10, it works, but that's in one particular browser. Different browsers behave differently and might make more parallel requests. No matter what I increase the limit to, there's always the possibility of a connection being aborted because the limit is reached without some for of queuing mechanism available.

bplant

2013-08-12 13:18

reporter   ~0007348

Possibly a little bit naughty, but what about a #ifdef to determine if the socket should be closed or not? It wouldn't break backwards compatibility (they wouldn't have the option defined), it wouldn't create an extra API function and it resolves my issue :-)

Christian Grothoff

2013-08-12 13:52

manager   ~0007349

>> How would I distinguish between normal connections and those that I add using MHD_add_connection? << -- MHD_get_connection_info can be used to get the socket (and then you can check if the number matches).

And if you know that out of 10 connections, you reserved 1 for MHD_add_connection and that one is in use, you know you must wait to queue another unless you're willing to risk to fail. The bigger issue is that if the server is idle (0 of the other 9 are in use), you'd still only be able to queue one connection via MHD_add_connection.

bplant

2013-08-12 14:19

reporter   ~0007350

That's probably going to vary depending on the use case. My use case is a web interface to a piece of hardware. It's very unlikely that there will be more than 2 people accessing the web interface concurrently. Therefore in a perfect world the whole 10 (or 5 as it was originally set to) connection slots could be used by either traditional connections or those added via MHD_add_connection.

Christian Grothoff

2013-08-12 14:53

manager   ~0007351

Right, but if you were to divide them up into two groups, say 5+5, would that be OK?

bplant

2013-08-12 15:02

reporter   ~0007352

It would work provided that the counting was accurate. Is it as simple as decrementing the "in-use count" when MHD_RequestCompletedCallback() fires and incrementing it whenever MHD_add_connection returns MHD_YES?

Christian Grothoff

2013-08-12 15:04

manager   ~0007353

Yes, it _should_ be that simple.

Christian Grothoff

2013-08-12 23:59

manager   ~0007361

Here's another (big) hack: use a negative FD. We could add a rule that says that if the FD is negative, MHD_add_connection must not close it on error. So that's like a one-bit option. (Naturally, if fd < 0, we'd use -fd for the file descriptor internally.). This fails if your FD might be zero AND you need this feature, but for 99.9999% of all users FD 0 is stdin, and if stdin was closed, it should be the listen socket, so the cases where the socket passed to MHD_add_connection is ZERO and you must not close it (because the server is busy on all connections) seems pretty extreme to the point of not being relevant. What do you think?

bplant

2013-08-13 00:28

reporter   ~0007362

What if there was an api call that returned the number of available connection slots?

Christian Grothoff

2013-08-13 08:57

manager   ~0007363

With threads, whatever that API returns might be invalid the next instruction (race).

bplant

2013-08-13 14:13

reporter   ~0007365

Thanks for all the suggestions. I'm wondering it perhaps it would be easier if I just modified the MHD source code myself to suit my purposes. I don't like to do this as these sorts of changes often get forgotten about which cause things to break when libraries are upgraded down the track, but I've only got 256KB of program memory to play with and I'm already having to trim other stuff down to get things to fit, so I can't really justify adding code to lock/unlock a mutex to maintain a counter when I can instead comment out one line of code.

Christian Grothoff

2013-08-13 14:36

manager   ~0007366

I agree, given that you're having some very special use-case on a very constraint system, maybe this is the best solution. I understand that this is not perfect, but at least your 'diff' to the code is tiny.

Issue History

Date Modified Username Field Change
2013-08-10 11:47 bplant New Issue
2013-08-10 20:32 Christian Grothoff Note Added: 0007327
2013-08-10 20:41 Christian Grothoff Note Added: 0007328
2013-08-10 20:41 Christian Grothoff Status new => resolved
2013-08-10 20:41 Christian Grothoff Fixed in Version => 0.9.29
2013-08-10 20:41 Christian Grothoff Resolution open => fixed
2013-08-10 20:41 Christian Grothoff Assigned To => Christian Grothoff
2013-08-10 20:42 Christian Grothoff Target Version => 0.9.29
2013-08-11 23:25 bplant Note Added: 0007337
2013-08-11 23:25 bplant Status resolved => feedback
2013-08-11 23:25 bplant Resolution fixed => reopened
2013-08-11 23:40 Christian Grothoff Note Added: 0007341
2013-08-12 00:03 bplant Note Added: 0007342
2013-08-12 00:03 bplant Status feedback => assigned
2013-08-12 00:42 Christian Grothoff Note Added: 0007343
2013-08-12 11:18 bplant Note Added: 0007345
2013-08-12 11:23 Christian Grothoff Note Added: 0007346
2013-08-12 12:19 bplant Note Added: 0007347
2013-08-12 13:18 bplant Note Added: 0007348
2013-08-12 13:52 Christian Grothoff Note Added: 0007349
2013-08-12 14:19 bplant Note Added: 0007350
2013-08-12 14:53 Christian Grothoff Note Added: 0007351
2013-08-12 15:02 bplant Note Added: 0007352
2013-08-12 15:04 Christian Grothoff Note Added: 0007353
2013-08-12 23:59 Christian Grothoff Note Added: 0007361
2013-08-13 00:28 bplant Note Added: 0007362
2013-08-13 08:57 Christian Grothoff Note Added: 0007363
2013-08-13 14:13 bplant Note Added: 0007365
2013-08-13 14:36 Christian Grothoff Note Added: 0007366
2013-08-13 14:36 Christian Grothoff Severity major => feature
2013-08-13 14:36 Christian Grothoff Status assigned => closed
2013-08-13 14:36 Christian Grothoff Resolution reopened => won't fix
2024-01-21 13:24 Christian Grothoff Category libmicrohttpd API => external API