diff --git a/bin/named/tcpclient.c b/bin/named/tcpclient.c index 09e157dd31..3b4dd3165e 100644 --- a/bin/named/tcpclient.c +++ b/bin/named/tcpclient.c @@ -219,7 +219,7 @@ tcp_recv_len(isc_task_t *task, isc_event_t *event) region.base = ctx->buf; region.length = ctx->buflen; - isc_socket_recv(sock, ®ion, ISC_FALSE, + isc_socket_recv(sock, ®ion, 0, task, tcp_recv_req, event->arg); isc_event_free(&event); @@ -349,7 +349,7 @@ tcp_accept(isc_task_t *task, isc_event_t *event) region.length = 2; region.base = (unsigned char *)&ctx->buflen; - RUNTIME_CHECK(isc_socket_recv(ctx->csock, ®ion, ISC_FALSE, task, + RUNTIME_CHECK(isc_socket_recv(ctx->csock, ®ion, 0, task, tcp_recv_len, ctx) == ISC_R_SUCCESS); @@ -399,7 +399,7 @@ tcp_send(isc_task_t *task, isc_event_t *event) */ region.base = (unsigned char *)&ctx->buflen; region.length = 2; - isc_socket_recv(sock, ®ion, ISC_FALSE, task, tcp_recv_len, ctx); + isc_socket_recv(sock, ®ion, 0, task, tcp_recv_len, ctx); isc_event_free(&event); } diff --git a/bin/named/udpclient.c b/bin/named/udpclient.c index e2616019ae..e0ac602082 100644 --- a/bin/named/udpclient.c +++ b/bin/named/udpclient.c @@ -177,7 +177,7 @@ udp_recv(isc_task_t *task, isc_event_t *event) &dev->address); } else { /* Send no reply, just wait for the next request. */ - isc_socket_recv(sock, ®ion, ISC_FALSE, task, udp_recv, ctx); + isc_socket_recv(sock, ®ion, 0, task, udp_recv, ctx); } isc_event_free(&event); @@ -218,7 +218,7 @@ udp_send(isc_task_t *task, isc_event_t *event) region.base = ctx->buf; region.length = UDP_INPUT_BUFFER_SIZE; - isc_socket_recv(sock, ®ion, ISC_FALSE, task, udp_recv, ctx); + isc_socket_recv(sock, ®ion, 0, task, udp_recv, ctx); isc_event_free(&event); } @@ -309,7 +309,7 @@ udp_listener_start(udp_listener_t *l, region.base = l->ctxs[i]->buf; RUNTIME_CHECK(isc_socket_recv(sock, ®ion, - ISC_FALSE, l->tasks[i], + 0, l->tasks[i], udp_recv, l->ctxs[i]) == ISC_R_SUCCESS); diff --git a/bin/tests/sock_test.c b/bin/tests/sock_test.c index 5a865f5684..4d443598cc 100644 --- a/bin/tests/sock_test.c +++ b/bin/tests/sock_test.c @@ -84,7 +84,7 @@ my_recv(isc_task_t *task, isc_event_t *event) if (strcmp(event->arg, "so2") != 0) { region = dev->region; sprintf(buf, "\r\nReceived: %.*s\r\n\r\n", - (int)region.length, (char *)region.base); + (int)dev->n, (char *)region.base); region.base = isc_mem_get(mctx, strlen(buf) + 1); region.length = strlen(buf) + 1; strcpy((char *)region.base, buf); /* strcpy is safe */ @@ -92,11 +92,10 @@ my_recv(isc_task_t *task, isc_event_t *event) } else { region = dev->region; printf("\r\nReceived: %.*s\r\n\r\n", - (int)region.length, (char *)region.base); + (int)dev->n, (char *)region.base); } - isc_socket_recv(sock, &dev->region, ISC_FALSE, - task, my_recv, event->arg); + isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->arg); isc_event_free(&event); } @@ -146,8 +145,7 @@ my_http_get(isc_task_t *task, isc_event_t *event) return; } - isc_socket_recv(sock, &dev->region, ISC_FALSE, task, my_recv, - event->arg); + isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->arg); isc_event_free(&event); } @@ -218,7 +216,7 @@ my_listen(isc_task_t *task, isc_event_t *event) newtask = NULL; RUNTIME_CHECK(isc_task_create(manager, NULL, 0, &newtask) == ISC_R_SUCCESS); - isc_socket_recv(dev->newsocket, ®ion, ISC_FALSE, + isc_socket_recv(dev->newsocket, ®ion, 1, newtask, my_recv, event->arg); isc_task_detach(&newtask); } else { diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 192e5c9663..5b6677027d 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -761,7 +761,7 @@ startrecv(dns_dispatch_t *disp) return; XDEBUG(("Recv into %p, length %d\n", region.base, region.length)); - res = isc_socket_recv(disp->socket, ®ion, ISC_TRUE, + res = isc_socket_recv(disp->socket, ®ion, 1, disp->task, udp_recv, disp); if (res != ISC_R_SUCCESS) { disp->shutdown_why = res; diff --git a/lib/dns/tcpmsg.c b/lib/dns/tcpmsg.c index d95bbafad1..922f2d7481 100644 --- a/lib/dns/tcpmsg.c +++ b/lib/dns/tcpmsg.c @@ -81,7 +81,7 @@ recv_length(isc_task_t *task, isc_event_t *ev_in) isc_buffer_init(&tcpmsg->buffer, region.base, region.length, ISC_BUFFERTYPE_BINARY); - result = isc_socket_recv(tcpmsg->sock, ®ion, ISC_FALSE, + result = isc_socket_recv(tcpmsg->sock, ®ion, 0, task, recv_message, tcpmsg); if (result != ISC_R_SUCCESS) { tcpmsg->result = result; @@ -188,7 +188,7 @@ dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, region.base = (unsigned char *)&tcpmsg->size; region.length = 2; /* isc_uint16_t */ - result = isc_socket_recv(tcpmsg->sock, ®ion, ISC_FALSE, + result = isc_socket_recv(tcpmsg->sock, ®ion, 0, tcpmsg->task, recv_length, tcpmsg); if (result != ISC_R_SUCCESS) diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index c8b339ab1f..b0392f3dcb 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -82,7 +82,7 @@ typedef struct isc_socketevent isc_socketevent_t; struct isc_socketevent { ISC_EVENT_COMMON(isc_socketevent_t); isc_result_t result; /* OK, EOF, whatever else */ - isc_boolean_t partial; /* partial i/o ok */ + unsigned int minimum; /* minimum i/o for event */ unsigned int n; /* bytes read or written */ isc_region_t region; /* the region info */ isc_sockaddr_t address; /* source address */ @@ -113,12 +113,8 @@ struct isc_socket_connev { /* * Internal events. */ -#define ISC_SOCKEVENT_INTRECV (ISC_EVENTCLASS_SOCKET + 257) -#define ISC_SOCKEVENT_INTSEND (ISC_EVENTCLASS_SOCKET + 258) -#define ISC_SOCKEVENT_INTACCEPT (ISC_EVENTCLASS_SOCKET + 259) -#define ISC_SOCKEVENT_INTCONN (ISC_EVENTCLASS_SOCKET + 260) -#define ISC_SOCKEVENT_INTR (ISC_EVENTCLASS_SOCKET + 261) -#define ISC_SOCKEVENT_INTW (ISC_EVENTCLASS_SOCKET + 262) +#define ISC_SOCKEVENT_INTR (ISC_EVENTCLASS_SOCKET + 256) +#define ISC_SOCKEVENT_INTW (ISC_EVENTCLASS_SOCKET + 257) typedef enum { isc_sockettype_udp = 1, @@ -413,7 +409,7 @@ isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp); isc_result_t isc_socket_recv(isc_socket_t *sock, isc_region_t *region, - isc_boolean_t partial, + unsigned int minimum, isc_task_t *task, isc_taskaction_t action, void *arg); /* * Receive from 'socket', storing the results in region. @@ -422,17 +418,17 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, * * Let 'length' refer to the length of 'region'. * - * If 'partial' is true, then at most 'length' bytes will be read. - * Otherwise the read will not complete until exactly 'length' bytes - * have been read. + * If 'minimum' is non-zero and at least that many bytes are read, + * the completion event will be posted to the task 'task.' If minimum + * is zero, the exact number of bytes requested in the region must + * be read for an event to be posted. This only makes sense for TCP + * connections, and is always set to the full buffer for UDP. * * The read will complete when the desired number of bytes have been * read, if end-of-input occurs, or if an error occurs. A read done * event with the given 'action' and 'arg' will be posted to the * event queue of 'task'. * - * Partial reads are always turned on for UDP. - * * The caller may neither read from nor write to 'region' until it * has received the read completion event. * diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index b55feb55c9..9d501e7d51 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -359,7 +359,7 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR, NULL, sock, sock, NULL, NULL); ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t), - ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR, + ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW, NULL, sock, sock, NULL, NULL); sock->magic = SOCKET_MAGIC; @@ -835,6 +835,8 @@ internal_recv(isc_task_t *me, isc_event_t *ev) (void)me; + INSIST(ev->type == ISC_SOCKEVENT_INTR); + sock = ev->sender; REQUIRE(VALID_SOCKET(sock)); @@ -965,7 +967,7 @@ internal_recv(isc_task_t *me, isc_event_t *ev) * was read with a success result, and continue * the loop. */ - if (dev->partial) { + if (dev->minimum >= dev->n) { send_recvdone_event(sock, &task, &dev, ISC_R_SUCCESS, 1); goto next; @@ -1010,6 +1012,8 @@ internal_send(isc_task_t *me, isc_event_t *ev) (void)me; + INSIST(ev->type == ISC_SOCKEVENT_INTW); + /* * Find out what socket this is and lock it. */ @@ -1544,9 +1548,8 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) } isc_result_t -isc_socket_recv(isc_socket_t *sock, isc_region_t *region, - isc_boolean_t partial, isc_task_t *task, - isc_taskaction_t action, void *arg) +isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum, + isc_task_t *task, isc_taskaction_t action, void *arg) { isc_socketevent_t *dev; isc_socketmgr_t *manager; @@ -1557,6 +1560,7 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, REQUIRE(VALID_SOCKET(sock)); manager = sock->manager; REQUIRE(VALID_MANAGER(manager)); + REQUIRE(region->length >= minimum); LOCK(&sock->lock); @@ -1574,12 +1578,17 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, * UDP sockets are always partial read */ if (sock->type == isc_sockettype_udp) - partial = ISC_TRUE; + dev->minimum = 1; + else { + if (minimum == 0) + dev->minimum = region->length; + else + dev->minimum = minimum; + } dev->region = *region; dev->n = 0; dev->result = ISC_R_SUCCESS; - dev->partial = partial; was_empty = ISC_LIST_EMPTY(sock->recv_list); @@ -1666,7 +1675,7 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, /* * Partial reads need to be queued */ - if ((size_t)cc != dev->region.length && !partial) + if (((size_t)cc != dev->region.length) && (dev->n < dev->minimum)) goto queue; /* @@ -1742,7 +1751,7 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, dev->region = *region; dev->n = 0; dev->result = ISC_R_SUCCESS; - dev->partial = ISC_FALSE; /* doesn't matter */ + dev->minimum = region->length; was_empty = ISC_LIST_EMPTY(sock->send_list); @@ -2424,7 +2433,7 @@ isc_socket_recvmark(isc_socket_t *sock, isc_task_attach(task, &ntask); dev->result = ISC_R_SUCCESS; - dev->partial = ISC_FALSE; /* doesn't matter */ + dev->minimum = 0; dev->sender = ntask; ISC_LIST_ENQUEUE(sock->recv_list, dev, link); @@ -2481,7 +2490,7 @@ isc_socket_sendmark(isc_socket_t *sock, isc_task_attach(task, &ntask); dev->result = ISC_R_SUCCESS; - dev->partial = ISC_FALSE; /* doesn't matter */ + dev->minimum = 0; dev->sender = ntask; ISC_LIST_ENQUEUE(sock->send_list, dev, link);