Author: rhuijben Date: Sat Nov 28 23:58:58 2015 New Revision: 1717013 URL: http://svn.apache.org/viewvc?rev=1717013&view=rev Log: Add a protocol callback for a cleanup step before the requests are done. This allows cleaning up writer state and thereby avoids segfaults when buckets are destroyed out of order.
This should solve a segfault/abort() in the Subversion over H2 issue I'm debugging. * incoming.c (serf_incoming_set_framing_type, serf_incoming_create2): Hook pre teardown. * outgoing.c (reset_connection, serf_connection_create, serf_connection_close, serf_connection_set_framing_type): Hook pre teardown. * protocols/http2_protocol.c (http2_outgoing_pre_teardown, http2_incoming_pre_teardown): New prototypes. (serf__http2_protocol_init, serf__http2_protocol_init_server): Hook teardown. (http2_outgoing_pre_teardown, http2_incoming_pre_teardown): New function. * protocols/http2_protocol.h (serf_http2__stream_pre_cleanup): New function. * protocols/http2_stream.c (serf_http2__stream_pre_cleanup): New function. Destroy data tail here instead of... (serf_http2__stream_cleanup): ... here. * serf_private.h (serf_incoming_t, serf_connection_t): New callback. Modified: serf/trunk/incoming.c serf/trunk/outgoing.c serf/trunk/protocols/http2_protocol.c serf/trunk/protocols/http2_protocol.h serf/trunk/protocols/http2_stream.c serf/trunk/serf_private.h Modified: serf/trunk/incoming.c URL: http://svn.apache.org/viewvc/serf/trunk/incoming.c?rev=1717013&r1=1717012&r2=1717013&view=diff ============================================================================== --- serf/trunk/incoming.c (original) +++ serf/trunk/incoming.c Sat Nov 28 23:58:58 2015 @@ -393,6 +393,8 @@ void serf_incoming_set_framing_type( /* Close down existing protocol */ if (client->protocol_baton && client->perform_teardown) { + if (client->perform_pre_teardown) + client->perform_pre_teardown(client); client->perform_teardown(client); client->protocol_baton = NULL; } @@ -402,6 +404,7 @@ void serf_incoming_set_framing_type( client->perform_write = write_to_client; client->perform_hangup = hangup_client; client->perform_teardown = NULL; + client->perform_pre_teardown = NULL; switch (framing_type) { case SERF_CONNECTION_FRAMING_TYPE_HTTP2: @@ -591,6 +594,7 @@ apr_status_t serf_incoming_create2( ic->perform_write = write_to_client; ic->perform_hangup = hangup_client; ic->perform_teardown = NULL; + ic->perform_pre_teardown = NULL; ic->current_request = NULL; ic->desc.desc_type = APR_POLL_SOCKET; Modified: serf/trunk/outgoing.c URL: http://svn.apache.org/viewvc/serf/trunk/outgoing.c?rev=1717013&r1=1717012&r2=1717013&view=diff ============================================================================== --- serf/trunk/outgoing.c (original) +++ serf/trunk/outgoing.c Sat Nov 28 23:58:58 2015 @@ -492,6 +492,9 @@ static apr_status_t reset_connection(ser serf__connection_pre_cleanup(conn); + if (conn->perform_pre_teardown) + conn->perform_pre_teardown(conn); + /* First, cancel all written requests for which we haven't received a response yet. Inform the application that the request is cancelled, so it can requeue them if needed. */ @@ -564,6 +567,7 @@ static apr_status_t reset_connection(ser conn->perform_write = write_to_connection; conn->perform_hangup = hangup_connection; conn->perform_teardown = NULL; + conn->perform_pre_teardown = NULL; conn->perform_cancel_request = NULL; conn->perform_prioritize_request = NULL; @@ -1248,6 +1252,7 @@ serf_connection_t *serf_connection_creat conn->perform_write = write_to_connection; conn->perform_hangup = hangup_connection; conn->perform_teardown = NULL; + conn->perform_pre_teardown = NULL; conn->perform_cancel_request = NULL; conn->perform_prioritize_request = NULL; conn->protocol_baton = NULL; @@ -1359,6 +1364,9 @@ apr_status_t serf_connection_close( requests as fully written, allowing more efficient cleanup */ serf__connection_pre_cleanup(conn); + if (conn->perform_pre_teardown) + conn->perform_pre_teardown(conn); + /* The application asked to close the connection, no need to notify it for each cancelled request. */ while (conn->written_reqs) { @@ -1463,6 +1471,8 @@ void serf_connection_set_framing_type( /* Close down existing protocol */ if (conn->protocol_baton) { + if (conn->perform_pre_teardown) + conn->perform_pre_teardown(conn); conn->perform_teardown(conn); conn->protocol_baton = NULL; } @@ -1475,6 +1485,7 @@ void serf_connection_set_framing_type( conn->perform_cancel_request = NULL; conn->perform_prioritize_request = NULL; conn->perform_teardown = NULL; + conn->perform_pre_teardown = NULL; switch (framing_type) { case SERF_CONNECTION_FRAMING_TYPE_HTTP2: Modified: serf/trunk/protocols/http2_protocol.c URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1717013&r1=1717012&r2=1717013&view=diff ============================================================================== --- serf/trunk/protocols/http2_protocol.c (original) +++ serf/trunk/protocols/http2_protocol.c Sat Nov 28 23:58:58 2015 @@ -43,6 +43,9 @@ http2_outgoing_hangup(serf_connection_t static void http2_outgoing_teardown(serf_connection_t *conn); +static void +http2_outgoing_pre_teardown(serf_connection_t *conn); + static apr_status_t http2_incoming_read(serf_incoming_t *client); @@ -55,6 +58,9 @@ http2_incoming_hangup(serf_incoming_t *c static void http2_incoming_teardown(serf_incoming_t *conn); +static void +http2_incoming_pre_teardown(serf_incoming_t *conn); + static apr_status_t http2_process(serf_http2_protocol_t *h2); @@ -345,6 +351,7 @@ void serf__http2_protocol_init(serf_conn conn->perform_write = http2_outgoing_write; conn->perform_hangup = http2_outgoing_hangup; conn->perform_teardown = http2_outgoing_teardown; + conn->perform_pre_teardown = http2_outgoing_pre_teardown; conn->perform_cancel_request = http2_cancel_request; conn->perform_prioritize_request = http2_prioritize_request; conn->protocol_baton = h2; @@ -428,6 +435,7 @@ void serf__http2_protocol_init_server(se client->perform_write = http2_incoming_write; client->perform_hangup = http2_incoming_hangup; client->perform_teardown = http2_incoming_teardown; + client->perform_pre_teardown = http2_incoming_pre_teardown; client->protocol_baton = h2; /* Send a settings frame */ @@ -1706,6 +1714,18 @@ http2_outgoing_hangup(serf_connection_t } static void +http2_outgoing_pre_teardown(serf_connection_t *conn) +{ + serf_http2_protocol_t *h2 = conn->protocol_baton; + serf_http2_stream_t *s = h2->first; + + while (s) { + serf_http2__stream_pre_cleanup(s); + s = s->next; + } +} + +static void http2_outgoing_teardown(serf_connection_t *conn) { serf_http2_protocol_t *ctx = conn->protocol_baton; @@ -1843,6 +1863,19 @@ http2_incoming_teardown(serf_incoming_t client->protocol_baton = NULL; } +static void +http2_incoming_pre_teardown(serf_incoming_t *conn) +{ + serf_http2_protocol_t *h2 = conn->protocol_baton; + serf_http2_stream_t *s = h2->first; + + while (s) { + serf_http2__stream_pre_cleanup(s); + s = s->next; + } +} + + void serf_http2__allocate_stream_id(void *baton, apr_int32_t *streamid) Modified: serf/trunk/protocols/http2_protocol.h URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.h?rev=1717013&r1=1717012&r2=1717013&view=diff ============================================================================== --- serf/trunk/protocols/http2_protocol.h (original) +++ serf/trunk/protocols/http2_protocol.h Sat Nov 28 23:58:58 2015 @@ -189,6 +189,10 @@ serf_http2__allocate_stream_id(void *bat void serf_http2__stream_cleanup(serf_http2_stream_t *stream); +void +serf_http2__stream_pre_cleanup(serf_http2_stream_t *stream); + + serf_http2_stream_t * serf_http2__stream_get(serf_http2_protocol_t *h2, apr_int32_t streamid, Modified: serf/trunk/protocols/http2_stream.c URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_stream.c?rev=1717013&r1=1717012&r2=1717013&view=diff ============================================================================== --- serf/trunk/protocols/http2_stream.c (original) +++ serf/trunk/protocols/http2_stream.c Sat Nov 28 23:58:58 2015 @@ -84,6 +84,15 @@ serf_http2__stream_create(serf_http2_pro } void +serf_http2__stream_pre_cleanup(serf_http2_stream_t *stream) +{ + if (stream->data) { + if (stream->data->data_tail) + serf_bucket_destroy(stream->data->data_tail); + } +} + +void serf_http2__stream_cleanup(serf_http2_stream_t *stream) { if (stream->data) { Modified: serf/trunk/serf_private.h URL: http://svn.apache.org/viewvc/serf/trunk/serf_private.h?rev=1717013&r1=1717012&r2=1717013&view=diff ============================================================================== --- serf/trunk/serf_private.h (original) +++ serf/trunk/serf_private.h Sat Nov 28 23:58:58 2015 @@ -458,6 +458,7 @@ struct serf_incoming_t { apr_status_t(*perform_hangup)(serf_incoming_t *client); /* Cleanup of protocol handling */ + void(*perform_pre_teardown)(serf_incoming_t *conn); void(*perform_teardown)(serf_incoming_t *conn); void *protocol_baton; @@ -575,6 +576,7 @@ struct serf_connection_t { apr_status_t (*perform_hangup)(serf_connection_t *conn); /* Cleanup of protocol handling */ + void(*perform_pre_teardown)(serf_connection_t *conn); void (*perform_teardown)(serf_connection_t *conn); void *protocol_baton;