Christian,

The purpose of the Web Server is to manage Services, as it is now it
provides an interface for the clients for them to interact with those
services, for example a performing a HTTP GET request on a Service will
return its value and performing a HTTP PUT request will set this value to
the given one. The Web Server can contain a lot of Services and have a lot
of clients.

In addition to that, one of the feature that I want to add is to be able to
receive notifications on value changes of certain services. To do so, each
client should be able to perform a GET on the URI "/events" in order to
engage the connection to these notifications. Then, whenever a Service
changes value, the server checks if the client has subscribed to that
service's notifications, and if so, it sends him a notification of the value
change with the new value.

For now on, this works well thanks to MHD_create_response_from_callback. All
clients receive notifications of the services that they subscribed to etc...

I have to admit that the choice of defining clients with IP addresses was
not well thought,indeed I used IP address as unique identifiers for each
client and didn't think of all the scenarios (even though the web server
aims at being run in a Local Area Network) I remodeled the notifications
part on the web server using Sessions, thank you for the advice !

Nevertheless, the segmentation fault still appears when I close and reopen
another connection, MHD tells me that it is impossible to send data due to a
"Broken Pipe", and goes into the request_completed callback. (the same
segmentation fault in my previous mail)

I just downgraded my MHD to 0.9.13 and it works like a charm ! (tried with
0.9.14 and SVN HEAD) Any idea why ?


On Thu, Sep 15, 2011 at 2:57 PM, Christian Grothoff
<[email protected]>wrote:

> Eh, MHD_connection_close is NOT part of the public API for good reasons.
>  You MUST not use it, the symbol is not even exported by the library.
> Getting segmentation faults from using it yourself is expected.  Do not do
> that.
>
> Also, I am getting more an more confused about what you're trying to do.
> Naturally you CAN get two connections from the same source IP address at the
> same time, and your server should support that (otherwise it is simply
> broken).  MHD has no problem handling more than one connection per IP at a
> time either.


> I currently can only conclude that you're trying to do something with IP
> addresses that you should manage with sessions/cookies and that your
> application logic is most likely severely broken (based on not understanding
> TCP/IP and/or HTTP) and thus you're trying to do these strange things and
> come up with odd requirements like the 'instant' cleanup on connection
> closure.
>
> TCP-FIN is not 'instant' and a browser may send us a TCP-SYN before we get
> the FIN, right? Not to mention, what would your system do with two users
> behind NAT using the same IP address?
>
> With SVN HEAD, MHD is now calling the response destroy handler (as well as
> the 'connection completed' handlers) as soon as the OS tells us that the
> connection is dead.  More cannot be done, and mucking around with MHD
> internals is not going to improve the situation.  Also, you should NEVER
> EVER store a 'struct MHD_Connection' in your own data structures, that's
> virtually always a bug.  Instead, store a pointer to your data structures in
> the 'void**' you're provided by MHD.
>
> Happy hacking!
>
> Christian
>
>
> On 09/15/2011 09:15 AM, Regis Louge wrote:
>
>> Hi,
>>
>> I have updated my version to the 0.9.14 that contains this patch
>> (without compilation error :) ). I managed to handle the disconnection
>> reconnection of the client by storing the MHD_Connection in my structure
>> and closing it manually whenever a call on "/push" is made from the same
>> IP address and a previous connection was stored :
>>
>> if(client->connection != NULL) MHD_connection_close(client->**connection,
>> MHD_REQUEST_TERMINATED_WITH_**ERROR);
>> client->connection = connection;
>>
>> Now I encounter something really weird, indeed, if a client disconnects,
>> I can "send" him a push notification without anything happening on my
>> web server, but when I "send" him a second one I have this weird
>> segmentation fault in :
>>
>> int MHD_connection_handle_write (struct MHD_Connection *connection)
>> |
>> |_switch (connection->state)
>>      |
>>      |_case MHD_CONNECTION_CHUNKED_BODY_**READY:
>>           |
>>           |_check_write_done (connection,
>>                             (connection->response->total_**size ==
>>                              connection->response_write_**position) ?
>>                             MHD_CONNECTION_BODY_SENT :
>>                             MHD_CONNECTION_CHUNKED_BODY_**UNREADY);
>>
>> It is right after the connection closes so connection->state is supposed
>> to be MHD_CONNECTION_CLOSED ?
>>
>> Any idea what that would happen ? And why does the first push
>> notification attempt don't fail ?
>>
>> Thanks a lot
>>
>> On Tue, Sep 13, 2011 at 9:48 AM, Christian Grothoff
>> <[email protected] <mailto:[email protected]**>> wrote:
>>
>>    Regis, here is a patch along the lines I'm thinking of (also in SVN
>>    HEAD).
>>
>>    $ svn diff
>>    Index: src/daemon/connection.c
>>    ==============================**==============================**
>> =======
>>    --- src/daemon/connection.c     (revision 16779)
>>    +++ src/daemon/connection.c     (working copy)
>>    @@ -316,6 +316,11 @@
>>           MHD_destroy_response (pos->response);
>>           pos->response = NULL;
>>         }
>>    +  if (pos->response != NULL)
>>    +    {
>>    +      MHD_destroy_response (pos->response);
>>    +      pos->response = NULL;
>>    +    }
>>      }
>>
>>    I suspect this might do the trick...
>>
>>    Happy hacking,
>>
>>    -Christian
>>
>>    On Tuesday, September 13, 2011 09:33:57 AM Regis Louge wrote:
>>     > Calling 'still connected' from what would inevidably be another
>>    thread is
>>     > not
>>     >
>>     > > safe (as in, there is a race and you can't be sure that the
>>    'connection'
>>     > > handle is not freed in the mean time), so that's not a solution.
>>     > >
>>     > > Can you motivate a bit better why you need this cleanup 'as fast
>> as
>>     > > possible'
>>     > > (and what exactly your constraints are here?)?  Reading Eivind's
>>     > > response, that would still not be 'as fast as possible', as 1s
>>    is still
>>     > > like an eternity
>>     > > for modern machines.
>>     >
>>     > What I want to create is a push notification communication between
>> my
>>     > server and clients that would want to subscribe to that
>>    communication,
>>     > indeed, when performing a GET on the URI "/push", a client would
>>    open this
>>     > connection and receive push notifications of what is happening on
>> the
>>     > server. Those notifications depend on the other activities on the
>>    server
>>     > (namely some PUT requests that it receives on other URI). Thus a
>>    client
>>     > should be able to subscribe to these notifications but also to
>>     > un-subscribe ! in the case of un-subscription, the client should
>>    also be
>>     > able to resubscribe as soon as possible. Let's take for example a
>>    client
>>     > crashing, when he recovers, he should be able to subscribe to
>>    this push
>>     > notification communication like nothing ever happens. Thus you
>>    are right
>>     > when you say that (at least for my case) 1s is an eternity.
>>     >
>>     > > An alternative direction might be for us to call the connection
>>    cleanup
>>     > > handler inside the thread and thus terminating the handler
>>    thread itself.
>>     > > That way, you would know instantly the connection is "gone" and
>>    could do
>>     > > your
>>     > > own cleanup --- even though the MHD per-connection memory
>>    itself has not
>>     > > been
>>     > > completely cleaned up (that would still happen upon the next
>>    connection
>>     > > inside
>>     > > of the main thread, I see little alternative to that). Would
>>    that work?
>>     >
>>     > I like the idea of knowing instantly that the connection is
>>    "gone" but I
>>     > don't really get how you would do it. When exactly would you call
>> the
>>     > connection cleanup handler in the thread ?
>>     >
>>     > > Happy hacking,
>>     > >
>>     > > Christian
>>     > >
>>     > > > On Fri, Sep 9, 2011 at 1:49 PM, Christian Grothoff
>>     > > >
>>     > > > <[email protected] <mailto:[email protected]**
>> >>wrote:
>>
>>     > > > > Hi Regis,
>>     > > > >
>>     > > > > I've written a new testcase based on your specifications,
>>    and I'm now
>>     > > > > even more
>>     > > > > convinced that there is no bug.  The testcase will shortly
>>    be in SVN
>>     > > > > HEAD. The test starts a MHD server (using most available
>>    threading
>>     > > > > modes) and forks
>>     > > > > a 'curl' process for the download. MHD then generates an
>>    "infiinte"
>>     > > > > webpage of
>>     > > > > "d" characters and the test driver eventually (after ~1s)
>>    kills curl
>>     > > > > (SIGTERM).  The test driver then checks that the cleanup
>>    function is
>>     > > > > indeed called.
>>     > > > >
>>     > > > > Now, there is one *unusual* case which might have tripped
>>    you up
>>     > > > > (certainly tripped me up when writing the testcase at
>>    first) in case
>>     > > > > of the multithreaded
>>     > > > > (one-thread-per-connection) MHD.  Here, the "cleanup"
>>    function is
>>     > > > > only called
>>     > > > > after MHD accepts the *next* inbound connection -- or upon MHD
>>     > >
>>     > > shutdown.
>>     > >
>>     > > > > The reason for this is simple: the master MHD thread sleeps
>>    until it
>>     > > > > is awoken
>>     > > > > from listen and only then cleans up 'left-over'
>>    connections. This,
>>     > > > > potentially
>>     > > > > 'untimely' cleanup is usually not an issue as it still avoids
>>     > > > > unbounded (or even large) resource consumption.  However,
>>    if you
>>     > > > > test with only a single connection and without
>>    MHD_daemon_stop, you
>>     > > > > would think that MHD failed to call your cleanup function.
>>      Just
>>     > > > > remember this: the API guarantees that your
>>     > > > > cleanup function will be called, but it makes no claims as
>>    to when
>>     > > > > exactly this will happen exactly.
>>     > > > >
>>     > > > >
>>     > > > > I hope this helps!
>>     > > > >
>>     > > > > Happy hacking!
>>     > > > >
>>     > > > > Christian
>>     > > > >
>>     > > > > On Thursday, September 08, 2011 08:41:46 PM Regis Louge wrote:
>>     > > > > > Here is my callback function :
>>     > > > > >
>>     > > > > > static ssize_t
>>     > > > > > push_callback (void *cls, uint64_t pos, char *buf, size_t
>>    max)
>>     > > > > > {
>>     > > > > >
>>     > > > > >     PushElement *push = cls;
>>     > > > > >     if(push->pushReceived == 1){
>>     > > > > >
>>     > > > > >         ...
>>     > > > > >         Store push data in buf
>>     > > > > >         ...
>>     > > > > >         return strlen(buf);
>>     > > > > >
>>     > > > > >     }
>>     > > > > >     else return 0;
>>     > > > > >
>>     > > > > > }
>>     > > > > >
>>     > > > > > In my answer_to_connection for the URL /push I have :
>>     > > > > >
>>     > > > > > response = MHD_create_response_from_**callback
>>    (MHD_SIZE_UNKNOWN,
>>     > > > > >
>>     > > > > >
>>      32 * 1024,
>>     > >
>>     > > &push_callback,
>>     > >
>>     > > > > >
>>      push,
>>     > > > > >
>>     > > > > > &push_free_callback);
>>     > > > > >
>>     > > > > >            if(response == NULL)
>>     > > > > >            {
>>     > > > > >
>>     > > > > >           return MHD_NO;
>>     > > > > >
>>     > > > > >            }
>>     > > > > >            MHD_add_response_header (response,
>> "Content-Type",
>>     > > > > > "text/html;
>>     > > > > >
>>     > > > > > charset=utf-8");
>>     > > > > >
>>     > > > > >            ret = MHD_queue_response (connection,
>> MHD_HTTP_OK,
>>     > > > > >            response); MHD_destroy_response (response);
>>     > > > > >            return ret;
>>     > > > > >
>>     > > > > > For a test case, when my client accesses to /push using
>>    curl -N
>>     > > > > > -GET ".../push" he receives all the push notifications
>>    like it is
>>     > > > > > suppose to, when I cancel it (^C), nothing happens on my
>>    server,
>>     > > > > > request_completed is not called and neither is
>>    push_free_callback
>>     > > > > > (which is the cleanup function)
>>     > > > > >
>>     > > > > > On Thu, Sep 8, 2011 at 8:19 PM, Christian Grothoff
>>     > > > > >
>>     > > > > > <[email protected]
>>    <mailto:[email protected]**>>wrote:
>>
>>     > > > > > > Hi!
>>     > > > > > >
>>     > > > > > > Can you provide some kind of testcase that shows that
>>    MHD doesn't
>>     > > > > > > properly call the cleanup function?
>>     > > > > > >
>>     > > > > > > Happy hacking!
>>     > > > > > >
>>     > > > > > > Christian
>>     > > > > > >
>>     > > > > > > On Thursday, September 08, 2011 12:56:13 PM Regis Louge
>>    wrote:
>>     > > > > > > > Hi,
>>     > > > > > > >
>>     > > > > > > > I am currently trying to implement push notifications
>>    using
>>     > > > > > > > libmicrohttpd and MHD_create_response_from_**callback
>>    returning 0
>>     > > > > > > > until an event triggers the push. This seems to work
>>    pretty
>>     > > > > > > > fine except for when the client interrupts the
>>    communication,
>>     > > > > > > > then the cleanup method is not called and thus
>>    creates a lot
>>     > > > > > > > of problems and impossibility to "subscribe" again to
>>    the push
>>     > > > > > > > stream.
>>     > > > > > > >
>>     > > > > > > > --
>>     > > > > > > > Regis
>>     >
>>     > Regis
>>
>>
>>
>>
>> --
>> Regis
>>
>
>


-- 
Régis LOUGE
Eleve Ingénieur 5° année - ECE Paris - Aalborg Universitet
Mail : [email protected]
Tel : +33 6 62 51 40 91

Reply via email to