From: Alan T. DeKok Date: Mon, 4 Jun 2018 01:21:50 +0000 (-0400) Subject: allow for partial writes to sockets. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=41b5ea24b4bf60fa60ac01529c3ad5b4fd637932;p=thirdparty%2Ffreeradius-server.git allow for partial writes to sockets. When that happens, save how much we've written, and remember to keep doing the writes later. --- diff --git a/src/lib/io/network.c b/src/lib/io/network.c index b955749b387..2abd0971f5b 100644 --- a/src/lib/io/network.c +++ b/src/lib/io/network.c @@ -80,6 +80,7 @@ typedef struct fr_network_socket_t { fr_message_set_t *ms; //!< message buffers for this socket. fr_channel_data_t *cd; //!< cached in case of allocation & read error size_t leftover; //!< leftover data from a previous read + size_t written; //!< however much we did in a partial write fr_channel_data_t *pending; //!< the currently pending partial packet fr_heap_t *waiting; //!< packets waiting to be written @@ -588,6 +589,12 @@ static void fr_network_write(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUS rad_assert(s->pending != NULL); + /* + * @todo - this code is much the same as in + * fr_network_post_event(). Fix it so we only have one + * copy! + */ + /* * Start with the currently pending message, and then * work through the priority heap. @@ -609,6 +616,23 @@ static void fr_network_write(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUS * pending message to the current one. */ if (errno == EWOULDBLOCK) { + s->pending = 0; + + save_pending: + /* + * s->pending MUST be localized. + * Other messages in the list + * MUST NOT have been localized + * yet. + */ + if (cd->m.status != FR_MESSAGE_LOCALIZED) { + fr_message_t *lm; + + MEM(lm = fr_message_localize(s, &cd->m, sizeof(*cd))); + fr_message_done(&cd->m); + + cd = (fr_channel_data_t *) lm; + } s->pending = cd; return; } @@ -631,13 +655,15 @@ static void fr_network_write(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUS } /* - * - We MUST have written all of the data. It is - * up to the app_io->write() function to track - * any partially written data. + * If we've done a partial write, localize the message and continue. */ - rad_assert((size_t) rcode == cd->m.data_size); + if ((rcode > 0) && ((size_t) rcode < cd->m.data_size)) { + s->written = rcode; + goto save_pending; + } + s->pending = NULL; + s->written = 0; /* * Reset for the next message. @@ -1202,6 +1228,9 @@ static void fr_network_post_event(UNUSED fr_event_list_t *el, UNUSED struct time cd->reply.request_time, cd->m.data, cd->m.data_size, 0); if (rcode < 0) { + s->pending = 0; + + save_pending: if (errno == EWOULDBLOCK) { if (fr_event_fd_insert(nr, nr->el, s->fd, fr_network_read, @@ -1245,14 +1274,18 @@ static void fr_network_post_event(UNUSED fr_event_list_t *el, UNUSED struct time } /* - * We MUST have written all of the data. It is - * up to the app_io->write() function to track - * any partially written data. + * If there's a partial write, save the write + * callback for later. */ - rad_assert(!rcode || (size_t) rcode == cd->m.data_size); + if ((rcode > 0) && ((size_t) rcode < cd->m.data_size)) { + s->written = rcode; + goto save_pending; + } DEBUG3("Sending reply to socket %d", s->fd); fr_message_done(&cd->m); + s->pending = NULL; + s->written = 0; /* * As a special case, allow write() to return