From: Mark Andrews Date: Fri, 17 Jan 2020 07:24:24 +0000 (+1100) Subject: add ISC_MAGIC and reference counting to httpd and httpdmgr X-Git-Tag: v9.16.0~51^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7c3f419d6628b2ebfcd86fdd3116b35001950819;p=thirdparty%2Fbind9.git add ISC_MAGIC and reference counting to httpd and httpdmgr --- diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index 648f43166fe..43c2954837b 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -61,10 +62,19 @@ #define HTTPD_CLOSE 0x0001 /* Got a Connection: close header */ #define HTTPD_FOUNDHOST 0x0002 /* Got a Host: header */ #define HTTPD_KEEPALIVE 0x0004 /* Got a Connection: Keep-Alive */ -#define HTTPD_ACCEPT_DEFLATE 0x0008 +#define HTTPD_ACCEPT_DEFLATE 0x0008 + +#define HTTPD_MAGIC ISC_MAGIC('H', 't', 'p', 'd') +#define VALID_HTTPD(m) ISC_MAGIC_VALID(m, HTTPD_MAGIC) + +#define HTTPDMGR_MAGIC ISC_MAGIC('H', 'p', 'd', 'm') +#define VALID_HTTPDMGR(m) ISC_MAGIC_VALID(m, HTTPDMGR_MAGIC) + /*% http client */ struct isc_httpd { + unsigned int magic; /* HTTPD_MAGIC */ + isc_refcount_t references; isc_httpdmgr_t *mgr; /*%< our parent */ ISC_LINK(isc_httpd_t) link; unsigned int state; @@ -126,6 +136,8 @@ struct isc_httpd { /*% lightweight socket manager for httpd output */ struct isc_httpdmgr { + unsigned int magic; /* HTTPDMGR_MAGIC */ + isc_refcount_t references; isc_mem_t *mctx; isc_socket_t *sock; /*%< listening socket */ isc_task_t *task; /*%< owning task */ @@ -222,8 +234,14 @@ destroy_client(isc_httpd_t **httpdp) { *httpdp = NULL; + if (isc_refcount_decrement(&httpd->references) != 1) { + return; + } + LOCK(&httpdmgr->lock); + httpd->magic = 0; + isc_refcount_destroy(&httpd->references); isc_socket_detach(&httpd->sock); ISC_LIST_UNLINK(httpdmgr->running, httpd, link); @@ -280,6 +298,8 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, ISC_LIST_INIT(httpdmgr->running); ISC_LIST_INIT(httpdmgr->urls); + isc_refcount_init(&httpdmgr->references, 1); + /* XXXMLG ignore errors on isc_socket_listen() */ result = isc_socket_listen(sock, SOMAXCONN); if (result != ISC_R_SUCCESS) { @@ -291,17 +311,24 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, (void)isc_socket_filter(sock, "httpready"); - result = isc_socket_accept(sock, task, isc_httpd_accept, httpdmgr); - if (result != ISC_R_SUCCESS) - goto cleanup; - httpdmgr->render_404 = render_404; httpdmgr->render_500 = render_500; + httpdmgr->magic = HTTPDMGR_MAGIC; + + isc_refcount_increment(&httpdmgr->references); + result = isc_socket_accept(sock, task, isc_httpd_accept, httpdmgr); + if (result != ISC_R_SUCCESS) { + (void) isc_refcount_decrement(&httpdmgr->references); + goto cleanup; + } *httpdmgrp = httpdmgr; return (ISC_R_SUCCESS); cleanup: + httpdmgr->magic = 0; + isc_refcount_decrement(&httpdmgr->references); + isc_refcount_destroy(&httpdmgr->references); isc_task_detach(&httpdmgr->task); isc_socket_detach(&httpdmgr->sock); isc_mem_detach(&httpdmgr->mctx); @@ -312,27 +339,20 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, static void httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) { - isc_mem_t *mctx; isc_httpdurl_t *url; ENTER("httpdmgr_destroy"); - LOCK(&httpdmgr->lock); - - if (!MSHUTTINGDOWN(httpdmgr)) { - NOTICE("httpdmgr_destroy not shutting down yet"); - UNLOCK(&httpdmgr->lock); + if (isc_refcount_decrement(&httpdmgr->references) != 1) { return; } - /* - * If all clients are not shut down, don't do anything yet. - */ - if (!ISC_LIST_EMPTY(httpdmgr->running)) { - NOTICE("httpdmgr_destroy clients still active"); - UNLOCK(&httpdmgr->lock); - return; - } + LOCK(&httpdmgr->lock); + + httpdmgr->magic = 0; + + INSIST(MSHUTTINGDOWN(httpdmgr)); + INSIST(ISC_LIST_EMPTY(httpdmgr->running)); NOTICE("httpdmgr_destroy detaching socket, task, and timermgr"); @@ -355,11 +375,11 @@ httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) { UNLOCK(&httpdmgr->lock); isc_mutex_destroy(&httpdmgr->lock); - if (httpdmgr->ondestroy != NULL) + if (httpdmgr->ondestroy != NULL) { (httpdmgr->ondestroy)(httpdmgr->cb_arg); - - mctx = httpdmgr->mctx; - isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t)); + } + isc_refcount_destroy(&httpdmgr->references); + isc_mem_putanddetach(&httpdmgr->mctx, httpdmgr, sizeof(isc_httpdmgr_t)); EXIT("httpdmgr_destroy"); } @@ -634,6 +654,8 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) { httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t)); + isc_refcount_init(&httpd->references, 1); + isc_refcount_increment(&httpdmgr->references); httpd->mgr = httpdmgr; ISC_LINK_INIT(httpd, link); ISC_LIST_APPEND(httpdmgr->running, httpd, link); @@ -652,20 +674,24 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) { isc_buffer_initnull(&httpd->bodybuffer); httpd->sendbuffer = NULL; reset_client(httpd); + httpd->magic = HTTPD_MAGIC; r.base = (unsigned char *)httpd->recvbuf; r.length = HTTP_RECVLEN - 1; result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone, httpd); - /* FIXME!!! */ - POST(result); + if (result != ISC_R_SUCCESS) { + destroy_client(&httpd); + } NOTICE("accept queued recv on socket"); requeue: + isc_refcount_increment(&httpdmgr->references); result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept, httpdmgr); if (result != ISC_R_SUCCESS) { - /* XXXMLG what to do? Log failure... */ + int32_t refs = isc_refcount_decrement(&httpdmgr->references); + INSIST(refs > 1); NOTICE("accept could not reaccept due to failure"); } @@ -834,24 +860,25 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { if (sev->result != ISC_R_SUCCESS) { NOTICE("recv destroying client"); - destroy_client(&httpd); goto out; } result = process_request(httpd, sev->n); if (result == ISC_R_NOTFOUND) { if (httpd->recvlen >= HTTP_RECVLEN - 1) { - destroy_client(&httpd); goto out; } r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen; r.length = HTTP_RECVLEN - httpd->recvlen - 1; - /* check return code? */ - (void)isc_socket_recv(httpd->sock, &r, 1, task, - isc_httpd_recvdone, httpd); + isc_refcount_increment(&httpd->references); + result = isc_socket_recv(httpd->sock, &r, 1, task, + isc_httpd_recvdone, httpd); + if (result != ISC_R_SUCCESS) { + uint32_t refs = isc_refcount_decrement(&httpd->references); + INSIST(refs > 1); + } goto out; } else if (result != ISC_R_SUCCESS) { - destroy_client(&httpd); goto out; } @@ -864,13 +891,16 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { isc_buffer_initnull(&httpd->bodybuffer); isc_time_now(&now); isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf)); + LOCK(&httpd->mgr->lock); url = ISC_LIST_HEAD(httpd->mgr->urls); while (url != NULL) { if (strcmp(httpd->url, url->url) == 0) break; url = ISC_LIST_NEXT(url, link); } - if (url == NULL) + UNLOCK(&httpd->mgr->lock); + + if (url == NULL) { result = httpd->mgr->render_404(httpd->url, NULL, httpd->querystring, NULL, NULL, @@ -880,7 +910,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { &httpd->bodybuffer, &httpd->freecb, &httpd->freecb_arg); - else + } else { result = url->action(httpd->url, url, httpd->querystring, httpd->headers, @@ -888,6 +918,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { &httpd->retcode, &httpd->retmsg, &httpd->mimetype, &httpd->bodybuffer, &httpd->freecb, &httpd->freecb_arg); + } if (result != ISC_R_SUCCESS) { result = httpd->mgr->render_500(httpd->url, url, httpd->querystring, @@ -911,8 +942,9 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { #endif isc_httpd_response(httpd); - if ((httpd->flags & HTTPD_KEEPALIVE) != 0) + if ((httpd->flags & HTTPD_KEEPALIVE) != 0) { isc_httpd_addheader(httpd, "Connection", "Keep-Alive"); + } isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype); isc_httpd_addheader(httpd, "Date", datebuf); isc_httpd_addheader(httpd, "Expires", datebuf); @@ -934,7 +966,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { if (is_compressed == true) { isc_httpd_addheader(httpd, "Content-Encoding", "deflate"); isc_httpd_addheaderuint(httpd, "Content-Length", - isc_buffer_usedlength(&httpd->compbuffer)); + isc_buffer_usedlength(&httpd->compbuffer)); } else { isc_httpd_addheaderuint(httpd, "Content-Length", isc_buffer_usedlength(&httpd->bodybuffer)); @@ -958,11 +990,16 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) { */ isc_buffer_usedregion(httpd->sendbuffer, &r); - /* check return code? */ - (void)isc_socket_send(httpd->sock, &r, task, - isc_httpd_senddone, httpd); + isc_refcount_increment(&httpd->references); + result = isc_socket_send(httpd->sock, &r, task, + isc_httpd_senddone, httpd); + if (result != ISC_R_SUCCESS) { + uint32_t refs = isc_refcount_decrement(&httpd->references); + INSIST(refs > 1); + } out: + destroy_client(&httpd); isc_event_free(&ev); EXIT("recv"); } @@ -971,8 +1008,11 @@ void isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) { isc_httpdmgr_t *httpdmgr; isc_httpd_t *httpd; + + REQUIRE(httpdmgrp != NULL); httpdmgr = *httpdmgrp; *httpdmgrp = NULL; + REQUIRE(VALID_HTTPDMGR(httpdmgr)); ENTER("isc_httpdmgr_shutdown"); @@ -991,6 +1031,8 @@ isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) { UNLOCK(&httpdmgr->lock); + httpdmgr_destroy(httpdmgr); + EXIT("isc_httpdmgr_shutdown"); } @@ -1019,6 +1061,8 @@ isc_httpd_response(isc_httpd_t *httpd) { isc_result_t result; unsigned int needlen; + REQUIRE(VALID_HTTPD(httpd)); + needlen = strlen(httpd->protocol) + 1; /* protocol + space */ needlen += 3 + 1; /* room for response code, always 3 bytes */ needlen += strlen(httpd->retmsg) + 2; /* return msg + CRLF */ @@ -1035,15 +1079,16 @@ isc_httpd_response(isc_httpd_t *httpd) { } isc_result_t -isc_httpd_addheader(isc_httpd_t *httpd, const char *name, - const char *val) -{ +isc_httpd_addheader(isc_httpd_t *httpd, const char *name, const char *val) { isc_result_t result; unsigned int needlen; + REQUIRE(VALID_HTTPD(httpd)); + needlen = strlen(name); /* name itself */ - if (val != NULL) + if (val != NULL) { needlen += 2 + strlen(val); /* : and val */ + } needlen += 2; /* CRLF */ while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) { @@ -1065,6 +1110,8 @@ isc_result_t isc_httpd_endheaders(isc_httpd_t *httpd) { isc_result_t result; + REQUIRE(VALID_HTTPD(httpd)); + while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) { result = grow_headerspace(httpd); if (result != ISC_R_SUCCESS) @@ -1080,6 +1127,8 @@ isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) { unsigned int needlen; char buf[sizeof "18446744073709551616"]; + REQUIRE(VALID_HTTPD(httpd)); + snprintf(buf, sizeof(buf), "%d", val); needlen = strlen(name); /* name itself */ @@ -1101,6 +1150,9 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) { isc_httpd_t *httpd = ev->ev_arg; isc_region_t r; isc_socketevent_t *sev = (isc_socketevent_t *)ev; + isc_result_t result; + + REQUIRE(VALID_HTTPD(httpd)); ENTER("senddone"); INSIST(ISC_HTTPD_ISSEND(httpd)); @@ -1124,12 +1176,10 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) { } if (sev->result != ISC_R_SUCCESS) { - destroy_client(&httpd); goto out; } if ((httpd->flags & HTTPD_CLOSE) != 0) { - destroy_client(&httpd); goto out; } @@ -1141,11 +1191,17 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) { r.base = (unsigned char *)httpd->recvbuf; r.length = HTTP_RECVLEN - 1; - /* check return code? */ - (void)isc_socket_recv(httpd->sock, &r, 1, task, - isc_httpd_recvdone, httpd); + + isc_refcount_increment(&httpd->references); + result = isc_socket_recv(httpd->sock, &r, 1, task, + isc_httpd_recvdone, httpd); + if (result != ISC_R_SUCCESS) { + uint32_t refs = isc_refcount_decrement(&httpd->references); + INSIST(refs > 1); + } out: + destroy_client(&httpd); isc_event_free(&ev); EXIT("senddone"); } @@ -1188,6 +1244,8 @@ isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url, { isc_httpdurl_t *item; + REQUIRE(VALID_HTTPDMGR(httpdmgr)); + if (url == NULL) { httpdmgr->render_404 = func; return (ISC_R_SUCCESS); @@ -1203,7 +1261,10 @@ isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url, isc_time_now(&item->loadtime); ISC_LINK_INIT(item, link); + + LOCK(&httpdmgr->lock); ISC_LIST_APPEND(httpdmgr->urls, item, link); + UNLOCK(&httpdmgr->lock); return (ISC_R_SUCCESS); }