Add isc_socket_sendv(), sendtov(), and recvv() that work

This commit is contained in:
Michael Graff
1999-09-06 04:44:40 +00:00
parent 8c68207dfa
commit c520793fb9
2 changed files with 148 additions and 76 deletions

View File

@@ -61,7 +61,7 @@
#include <isc/lang.h>
#include <isc/boolean.h>
#include <isc/buffer.h>
#include <isc/bufferlist.h>
#include <isc/result.h>
#include <isc/event.h>
#include <isc/eventclass.h>
@@ -97,7 +97,7 @@ struct isc_socketevent {
unsigned int n; /* bytes read or written */
unsigned int offset; /* offset into buffer list */
isc_region_t region; /* for single-buffer i/o */
ISC_LIST(isc_buffer_t) bufferlist; /* list of buffers */
isc_bufferlist_t bufferlist; /* list of buffers */
isc_sockaddr_t address; /* source address */
};
@@ -428,12 +428,17 @@ isc_result_t
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_result_t
isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
unsigned int minimum,
isc_task_t *task, isc_taskaction_t action, void *arg);
/*
* Receive from 'socket', storing the results in region.
*
* Notes:
*
* Let 'length' refer to the length of 'region'.
* Let 'length' refer to the length of 'region' or to the sum of all
* available regions in the list of buffers '*buflist'.
*
* 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
@@ -446,59 +451,11 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region,
* event with the given 'action' and 'arg' will be posted to the
* event queue of 'task'.
*
* The caller may neither read from nor write to 'region' until it
* has received the read completion event.
* The caller may not modify 'region', the buffers which are passed
* into this function, or any data they refer to until the completion
* event is received.
*
* Requires:
*
* 'socket' is a valid socket
*
* 'region' is a valid region
*
* 'minimum' <= region.length
*
* 'task' is a valid task
*
* action != NULL and is a valid action
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*
* Event results:
*
* ISC_R_SUCCESS
* ISC_R_UNEXPECTED
* XXX needs other net-type errors
*/
isc_result_t
isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
unsigned int minimum,
isc_task_t *task, isc_taskaction_t action, void *arg);
/*
* Receive from 'socket', storing the results in region.
*
* Notes:
*
* Let 'length' refer to the sum of all available regions in the
* list of buffers 'buflist'.
*
* 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 buflist must
* be read for an event to be posted. This only makes sense for TCP
* connections, and is always set to 1 byte 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'.
*
* The caller may neither read from nor write to any buffer in the
* buffer list, nor may it link or unlink these buffers from any list.
* For isc_socket_recvv():
* On successful completion, '*buflist' will be empty, and the list of
* all buffers will be returned in the done event's 'bufferlist'
* member. On error return, '*buflist' will be unchanged.
@@ -507,9 +464,11 @@ isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
*
* 'socket' is a valid socket
*
* 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
* For isc_socket_recv():
* 'region' is a valid region
*
* 'minimum' is <= sum of all available regions.
* For isc_socket_recvv():
* 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
*
* 'task' is a valid task
*
@@ -535,34 +494,49 @@ isc_result_t
isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_sockaddr_t *address);
isc_result_t
isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *task, isc_taskaction_t action, void *arg);
isc_result_t
isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_sockaddr_t *address);
/*
* Send the contents of 'region' to the socket's peer.
*
* Notes:
*
* Shutting down the requestor's task *may* result in any
* still pending writes being dropped.
* still pending writes being dropped or completed, depending on the
* underlying OS implementation.
*
* If 'action' is NULL, then no completion event will be posted.
*
* The caller may neither read from nor write to 'region' until it
* has received the write completion event, or all references to the
* socket have been detached.
* The caller may not modify 'region', the buffers which are passed
* into this function, or any data they refer to until the completion
* event is received.
*
* For isc_socket_sendv() and isc_socket_sendtov():
* On successful completion, '*buflist' will be empty, and the list of
* all buffers will be returned in the done event's 'bufferlist'
* member. On error return, '*buflist' will be unchanged.
*
* Requires:
*
* 'socket' is a valid socket
*
* For isc_socket_send():
* 'region' is a valid region
*
* For isc_socket_sendv() and isc_socket_sendtov():
* 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
*
* 'task' is a valid task
*
* action == NULL or is a valid action
*
* Returns:
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED

View File

@@ -1879,7 +1879,6 @@ isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *ntask = NULL;
isc_boolean_t was_empty;
unsigned int iocount;
isc_region_t available;
isc_buffer_t *buffer;
REQUIRE(VALID_SOCKET(sock));
@@ -1891,12 +1890,7 @@ isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
manager = sock->manager;
REQUIRE(VALID_MANAGER(manager));
iocount = 0;
buffer = ISC_LIST_HEAD(*buflist);
while (buffer != NULL) {
isc_buffer_available(buffer, &available);
iocount += available.length;
}
iocount = isc_bufferlist_availablecount(buflist);
REQUIRE(iocount > 0);
LOCK(&sock->lock);
@@ -1925,8 +1919,6 @@ isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
dev->minimum = minimum;
}
dev->result = ISC_R_SUCCESS;
dev->n = 0;
dev->sender = task;
/*
@@ -1936,13 +1928,13 @@ isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
while (buffer != NULL) {
ISC_LIST_DEQUEUE(*buflist, buffer, link);
ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
buffer = ISC_LIST_HEAD(*buflist);
}
was_empty = ISC_LIST_EMPTY(sock->recv_list);
/*
* If the read queue is empty, try to do the I/O right now.
*/
was_empty = ISC_LIST_EMPTY(sock->recv_list);
if (!was_empty)
goto queue;
@@ -2127,8 +2119,6 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
LOCK(&sock->lock);
manager = sock->manager;
dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
if (dev == NULL) {
UNLOCK(&sock->lock);
@@ -2189,6 +2179,114 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
return (ISC_R_SUCCESS);
}
isc_result_t
isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *task, isc_taskaction_t action, void *arg)
{
return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL));
}
isc_result_t
isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_sockaddr_t *address)
{
isc_socketevent_t *dev;
isc_socketmgr_t *manager;
isc_task_t *ntask = NULL;
isc_boolean_t was_empty;
unsigned int iocount;
isc_buffer_t *buffer;
REQUIRE(VALID_SOCKET(sock));
REQUIRE(buflist != NULL);
REQUIRE(!ISC_LIST_EMPTY(*buflist));
REQUIRE(task != NULL);
REQUIRE(action != NULL);
manager = sock->manager;
REQUIRE(VALID_MANAGER(manager));
iocount = isc_bufferlist_usedcount(buflist);
REQUIRE(iocount > 0);
LOCK(&sock->lock);
dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
if (dev == NULL) {
UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
/***
*** From here down, only ISC_R_SUCCESS can be returned. Any further
*** error information will result in the done event being posted
*** to the task rather than this function failing.
***/
dev->sender = task;
set_dev_address(address, sock, dev);
/*
* Move each buffer from the passed in list to our internal one.
*/
buffer = ISC_LIST_HEAD(*buflist);
while (buffer != NULL) {
ISC_LIST_DEQUEUE(*buflist, buffer, link);
ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
buffer = ISC_LIST_HEAD(*buflist);
}
/*
* If the read queue is empty, try to do the I/O right now.
*/
was_empty = ISC_LIST_EMPTY(sock->send_list);
if (!was_empty)
goto queue;
if (sock->send_result != ISC_R_SUCCESS) {
send_senddone_event(sock, &dev, sock->send_result);
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
switch (doio_send(sock, dev)) {
case DOIO_SOFT:
goto queue;
break;
case DOIO_HARD:
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
break;
}
queue:
/*
* We couldn't send all or part of the request right now, so queue
* it.
*/
isc_task_attach(task, &ntask);
dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
/*
* Enqueue the request. If the socket was previously not being
* watched, poke the watcher to start paying attention to it.
*/
ISC_LIST_ENQUEUE(sock->send_list, dev, link);
if (was_empty)
select_poke(sock->manager, sock->fd);
XTRACE(TRACE_SEND,
("isc_socket_send: queued event %p, task %p\n", dev, ntask));
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
isc_result_t
isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr)
{