2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * Initialize a low-level ioq
42 hammer2_ioq_init(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq)
44 bzero(ioq, sizeof(*ioq));
45 ioq->state = HAMMER2_MSGQ_STATE_HEADER1;
46 TAILQ_INIT(&ioq->msgq);
50 hammer2_ioq_done(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq)
54 while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
55 TAILQ_REMOVE(&ioq->msgq, msg, entry);
58 if ((msg = ioq->msg) != NULL) {
65 * Initialize a low-level communications channel
68 hammer2_iocom_init(hammer2_iocom_t *iocom, int sock_fd, int alt_fd)
70 bzero(iocom, sizeof(*iocom));
72 TAILQ_INIT(&iocom->freeq);
73 TAILQ_INIT(&iocom->freeq_aux);
74 iocom->sock_fd = sock_fd;
75 iocom->alt_fd = alt_fd;
76 iocom->flags = HAMMER2_IOCOMF_RREQ | HAMMER2_IOCOMF_WIDLE;
77 hammer2_ioq_init(iocom, &iocom->ioq_rx);
78 hammer2_ioq_init(iocom, &iocom->ioq_tx);
81 * Negotiate session crypto synchronously. This will mark the
82 * connection as error'd if it fails.
84 hammer2_crypto_negotiate(iocom);
87 * Make sure our fds are set to non-blocking for the iocom core.
90 fcntl(sock_fd, F_SETFL, O_NONBLOCK);
92 /* if line buffered our single fgets() should be fine */
94 fcntl(alt_fd, F_SETFL, O_NONBLOCK);
99 hammer2_iocom_done(hammer2_iocom_t *iocom)
104 hammer2_ioq_done(iocom, &iocom->ioq_rx);
105 hammer2_ioq_done(iocom, &iocom->ioq_tx);
106 if ((msg = TAILQ_FIRST(&iocom->freeq)) != NULL) {
107 TAILQ_REMOVE(&iocom->freeq, msg, entry);
110 if ((msg = TAILQ_FIRST(&iocom->freeq_aux)) != NULL) {
111 TAILQ_REMOVE(&iocom->freeq_aux, msg, entry);
113 msg->aux_data = NULL;
119 * Allocate a new one-way message.
122 hammer2_allocmsg(hammer2_iocom_t *iocom, uint32_t cmd, int aux_size)
128 aux_size = (aux_size + HAMMER2_MSG_ALIGNMASK) &
129 ~HAMMER2_MSG_ALIGNMASK;
130 if ((msg = TAILQ_FIRST(&iocom->freeq_aux)) != NULL)
131 TAILQ_REMOVE(&iocom->freeq_aux, msg, entry);
133 if ((msg = TAILQ_FIRST(&iocom->freeq)) != NULL)
134 TAILQ_REMOVE(&iocom->freeq, msg, entry);
137 msg = malloc(sizeof(*msg));
139 msg->aux_data = NULL;
142 if (msg->aux_size != aux_size) {
145 msg->aux_data = NULL;
149 msg->aux_data = malloc(aux_size);
150 msg->aux_size = aux_size;
154 hbytes = (cmd & HAMMER2_MSGF_SIZE) * HAMMER2_MSG_ALIGN;
156 bzero(&msg->any.head, hbytes);
157 msg->any.head.aux_icrc = 0;
158 msg->any.head.cmd = cmd;
164 * Allocate a one-way or streaming reply to a message. The message is
165 * not modified. This function may be used to allocate multiple replies.
167 * If cmd is 0 then msg->any.head.cmd is used to formulate the reply command.
170 hammer2_allocreply(hammer2_msg_t *msg, uint32_t cmd, int aux_size)
173 hammer2_persist_t *pers;
175 assert((msg->any.head.cmd & HAMMER2_MSGF_REPLY) == 0);
177 cmd = msg->any.head.cmd;
179 rmsg = hammer2_allocmsg(msg->iocom, cmd, aux_size);
180 rmsg->any.head = msg->any.head;
181 rmsg->any.head.source = msg->any.head.target;
182 rmsg->any.head.target = msg->any.head.source;
183 rmsg->any.head.cmd = (cmd | HAMMER2_MSGF_REPLY) &
184 ~(HAMMER2_MSGF_CREATE | HAMMER2_MSGF_DELETE);
185 rmsg->any.head.aux_icrc = 0;
187 if ((pers = msg->persist) != NULL) {
188 assert(pers->lrep & HAMMER2_MSGF_DELETE);
189 rmsg->any.head.cmd |= pers->lrep & HAMMER2_MSGF_CREATE;
190 pers->lrep &= ~HAMMER2_MSGF_CREATE;
191 /* do not clear DELETE */
197 * Free a message so it can be reused afresh.
199 * NOTE: aux_size can be 0 with a non-NULL aux_data.
202 hammer2_freemsg(hammer2_msg_t *msg)
204 hammer2_iocom_t *iocom = msg->iocom;
207 TAILQ_INSERT_TAIL(&iocom->freeq_aux, msg, entry);
209 TAILQ_INSERT_TAIL(&iocom->freeq, msg, entry);
213 * I/O core loop for an iocom.
216 hammer2_iocom_core(hammer2_iocom_t *iocom,
217 void (*recvmsg_func)(hammer2_iocom_t *),
218 void (*sendmsg_func)(hammer2_iocom_t *),
219 void (*altmsg_func)(hammer2_iocom_t *))
221 struct pollfd fds[2];
224 iocom->recvmsg_callback = recvmsg_func;
225 iocom->sendmsg_callback = sendmsg_func;
226 iocom->altmsg_callback = altmsg_func;
228 while ((iocom->flags & HAMMER2_IOCOMF_EOF) == 0) {
231 fds[0].fd = iocom->sock_fd;
235 if (iocom->flags & HAMMER2_IOCOMF_RREQ)
236 fds[0].events |= POLLIN;
239 if ((iocom->flags & HAMMER2_IOCOMF_WIDLE) == 0) {
240 if (iocom->flags & HAMMER2_IOCOMF_WREQ)
241 fds[0].events |= POLLOUT;
246 if (iocom->alt_fd >= 0) {
247 fds[1].fd = iocom->alt_fd;
248 fds[1].events |= POLLIN;
250 poll(fds, 2, timeout);
252 poll(fds, 1, timeout);
254 if ((fds[0].revents & POLLIN) ||
255 (iocom->flags & HAMMER2_IOCOMF_RREQ) == 0) {
256 iocom->recvmsg_callback(iocom);
258 if ((iocom->flags & HAMMER2_IOCOMF_WIDLE) == 0) {
259 if ((fds[0].revents & POLLOUT) ||
260 (iocom->flags & HAMMER2_IOCOMF_WREQ) == 0) {
261 iocom->sendmsg_callback(iocom);
264 if (iocom->alt_fd >= 0 && (fds[1].revents & POLLIN))
265 iocom->altmsg_callback(iocom);
270 * Read the next ready message from the ioq, issuing I/O if needed.
271 * Caller should retry on a read-event when NULL is returned.
273 * If an error occurs during reception a HAMMER2_LNK_ERROR msg will
274 * be returned (and the caller must not call us again after that).
277 hammer2_ioq_read(hammer2_iocom_t *iocom)
279 hammer2_ioq_t *ioq = &iocom->ioq_rx;
281 hammer2_msg_hdr_t *head;
290 * If a message is already pending we can just remove and
293 if ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
294 TAILQ_REMOVE(&ioq->msgq, msg, entry);
299 * Message read in-progress (msg is NULL at the moment). We don't
300 * allocate a msg until we have its core header.
302 bytes = ioq->fifo_end - ioq->fifo_beg;
303 nmax = sizeof(iocom->rxbuf) - ioq->fifo_end;
307 case HAMMER2_MSGQ_STATE_HEADER1:
309 * Load the primary header, fail on any non-trivial read
310 * error or on EOF. Since the primary header is the same
311 * size is the message alignment it will never straddle
312 * the end of the buffer.
314 if (bytes < (int)sizeof(msg->any.head)) {
315 n = read(iocom->sock_fd,
316 iocom->rxbuf + ioq->fifo_end,
320 ioq->error = HAMMER2_IOQ_ERROR_EOF;
323 if (errno != EINTR &&
324 errno != EINPROGRESS &&
326 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
338 * Insufficient data accumulated (msg is NULL, caller will
342 if (bytes < (int)sizeof(msg->any.head))
346 head = (void *)(iocom->rxbuf + ioq->fifo_beg);
349 * XXX Decrypt the core header
353 * Check and fixup the core header. Note that the icrc
354 * has to be calculated before any fixups, but the crc
355 * fields in the msg may have to be swapped like everything
358 if (head->magic != HAMMER2_MSGHDR_MAGIC &&
359 head->magic != HAMMER2_MSGHDR_MAGIC_REV) {
360 ioq->error = HAMMER2_IOQ_ERROR_SYNC;
364 xcrc32 = hammer2_icrc32((char *)head + HAMMER2_MSGHDR_CRCOFF,
365 HAMMER2_MSGHDR_CRCBYTES);
366 if (head->magic == HAMMER2_MSGHDR_MAGIC_REV) {
367 hammer2_bswap_head(head);
368 flags |= HAMMER2_MSGX_BSWAPPED;
370 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
371 if (xcrc16 != head->icrc1) {
372 ioq->error = HAMMER2_IOQ_ERROR_HCRC;
377 * Calculate the full header size and aux data size
379 ioq->hbytes = (head->cmd & HAMMER2_MSGF_SIZE) *
381 ioq->abytes = head->aux_bytes * HAMMER2_MSG_ALIGN;
382 if (ioq->hbytes < (int)sizeof(msg->any.head) ||
383 ioq->hbytes > (int)sizeof(msg->any) ||
384 ioq->abytes > HAMMER2_MSGAUX_MAX) {
385 ioq->error = HAMMER2_IOQ_ERROR_FIELD;
390 * Finally allocate the message and copy the core header
391 * to the embedded extended header.
393 * Initialize msg->aux_size to 0 and use it to track
394 * the amount of data copied from the stream.
396 msg = hammer2_allocmsg(iocom, 0, ioq->abytes);
402 * We are either done or we fall-through
404 if (ioq->hbytes == sizeof(msg->any.head) && ioq->abytes == 0) {
405 bcopy(head, &msg->any.head, sizeof(msg->any.head));
406 ioq->fifo_beg += ioq->hbytes;
411 * Fall through to the next state. Make sure that the
412 * extended header does not straddle the end of the buffer.
413 * We still want to issue larger reads into our buffer,
414 * book-keeping is easier if we don't bcopy() yet.
416 if (bytes + nmax < ioq->hbytes) {
417 bcopy(iocom->rxbuf + ioq->fifo_beg, iocom->rxbuf,
420 ioq->fifo_end = bytes;
421 nmax = sizeof(iocom->rxbuf) - ioq->fifo_end;
423 ioq->state = HAMMER2_MSGQ_STATE_HEADER2;
425 case HAMMER2_MSGQ_STATE_HEADER2:
427 * Fill out the extended header.
430 if (bytes < ioq->hbytes) {
431 n = read(iocom->sock_fd,
432 msg->any.buf + ioq->fifo_end,
436 ioq->error = HAMMER2_IOQ_ERROR_EOF;
439 if (errno != EINTR &&
440 errno != EINPROGRESS &&
442 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
454 * Insufficient data accumulated (set msg NULL so caller will
457 if (bytes < ioq->hbytes) {
463 * XXX Decrypt the extended header
465 head = (void *)(iocom->rxbuf + ioq->fifo_beg);
468 * Check the crc on the extended header
470 if (ioq->hbytes > (int)sizeof(hammer2_msg_hdr_t)) {
471 xcrc32 = hammer2_icrc32(head + 1,
472 ioq->hbytes - sizeof(*head));
473 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
474 if (head->icrc2 != xcrc16) {
475 ioq->error = HAMMER2_IOQ_ERROR_XCRC;
481 * Copy the extended header into the msg and adjust the
484 bcopy(head, &msg->any, ioq->hbytes);
487 * We are either done or we fall-through.
489 if (ioq->abytes == 0) {
490 ioq->fifo_beg += ioq->hbytes;
495 * Must adjust nmax and bytes (and the state) when falling
498 ioq->fifo_beg += ioq->hbytes;
500 bytes -= ioq->hbytes;
501 ioq->state = HAMMER2_MSGQ_STATE_AUXDATA1;
503 case HAMMER2_MSGQ_STATE_AUXDATA1:
505 * Copy the partial or complete payload from remaining
506 * bytes in the FIFO. We have to fall-through either
507 * way so we can check the crc.
509 assert(msg->aux_size == 0);
510 if (bytes >= ioq->abytes) {
511 bcopy(iocom->rxbuf + ioq->fifo_beg, msg->aux_data,
513 msg->aux_size = ioq->abytes;
514 ioq->fifo_beg += ioq->abytes;
515 bytes -= ioq->abytes;
517 bcopy(iocom->rxbuf + ioq->fifo_beg, msg->aux_data,
519 msg->aux_size = bytes;
520 ioq->fifo_beg += bytes;
523 ioq->state = HAMMER2_MSGQ_STATE_AUXDATA2;
525 case HAMMER2_MSGQ_STATE_AUXDATA2:
527 * Read the remainder of the payload directly into the
528 * msg->aux_data buffer.
531 if (msg->aux_size < ioq->abytes) {
533 n = read(iocom->sock_fd,
534 msg->aux_data + msg->aux_size,
535 ioq->abytes - msg->aux_size);
538 ioq->error = HAMMER2_IOQ_ERROR_EOF;
541 if (errno != EINTR &&
542 errno != EINPROGRESS &&
544 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
554 * Insufficient data accumulated (set msg NULL so caller will
557 if (msg->aux_size < ioq->abytes) {
561 assert(msg->aux_size == ioq->abytes);
564 * XXX Decrypt the data
568 * Check aux_icrc, then we are done.
570 xcrc32 = hammer2_icrc32(msg->aux_data, msg->aux_size);
571 if (xcrc32 != msg->any.head.aux_icrc) {
572 ioq->error = HAMMER2_IOQ_ERROR_ACRC;
576 case HAMMER2_MSGQ_STATE_ERROR:
579 * We don't double-return errors, the caller should not
580 * have called us again after getting an error msg.
587 * Handle error, RREQ, or completion
589 * NOTE: nmax and bytes are invalid at this point, we don't bother
590 * to update them when breaking out.
594 * An unrecoverable error occured during processing,
595 * return a special error message. Try to leave the
596 * ioq state alone for post-mortem debugging.
598 * Link error messages are returned as one-way messages,
599 * so no flags get set. Source and target is 0 (link-level),
600 * msgid is 0 (link-level). All we really need to do is
601 * set up magic, cmd, and error.
603 assert(ioq->msg == msg);
605 msg = hammer2_allocmsg(iocom, 0, 0);
611 msg->aux_data = NULL;
614 bzero(&msg->any.head, sizeof(msg->any.head));
615 msg->any.head.magic = HAMMER2_MSGHDR_MAGIC;
616 msg->any.head.cmd = HAMMER2_LNK_ERROR;
617 msg->any.head.error = ioq->error;
618 ioq->state = HAMMER2_MSGQ_STATE_ERROR;
619 iocom->flags |= HAMMER2_IOCOMF_EOF;
620 } else if (msg == NULL) {
622 * Insufficient data received to finish building the message,
623 * set RREQ and return NULL.
625 * Leave ioq->msg intact.
626 * Leave the FIFO intact.
628 iocom->flags |= HAMMER2_IOCOMF_RREQ;
633 * Return msg, clear the FIFO if it is now empty.
634 * Flag RREQ if the caller needs to wait for a read-event
637 * The fifo has already been advanced past the message.
638 * Trivially reset the FIFO indices if possible.
640 if (ioq->fifo_beg == ioq->fifo_end) {
641 iocom->flags |= HAMMER2_IOCOMF_RREQ;
645 iocom->flags &= ~HAMMER2_IOCOMF_RREQ;
647 ioq->state = HAMMER2_MSGQ_STATE_HEADER1;
654 * Calculate the header and data crc's and write a low-level message to
655 * the connection. If aux_icrc is non-zero the aux_data crc is already
656 * assumed to have been set.
658 * A non-NULL msg is added to the queue but not necessarily flushed.
659 * Calling this function with msg == NULL will get a flush going.
662 hammer2_ioq_write(hammer2_msg_t *msg)
664 hammer2_iocom_t *iocom = msg->iocom;
665 hammer2_ioq_t *ioq = &iocom->ioq_tx;
672 TAILQ_INSERT_TAIL(&ioq->msgq, msg, entry);
674 hammer2_iocom_drain(iocom);
679 * Finish populating the msg fields
681 msg->any.head.magic = HAMMER2_MSGHDR_MAGIC;
682 msg->any.head.salt = (random() << 8) | (ioq->seq & 255);
686 * Calculate aux_icrc if 0, calculate icrc2, and finally
689 if (msg->aux_size && msg->any.head.aux_icrc == 0) {
690 assert((msg->aux_size & HAMMER2_MSG_ALIGNMASK) == 0);
691 xcrc32 = hammer2_icrc32(msg->aux_data, msg->aux_size);
692 msg->any.head.aux_icrc = xcrc32;
694 msg->any.head.aux_bytes = msg->aux_size / HAMMER2_MSG_ALIGN;
695 assert((msg->aux_size & HAMMER2_MSG_ALIGNMASK) == 0);
697 if ((msg->any.head.cmd & HAMMER2_MSGF_SIZE) >
698 sizeof(msg->any.head) / HAMMER2_MSG_ALIGN) {
699 hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) *
701 hbytes -= sizeof(msg->any.head);
702 xcrc32 = hammer2_icrc32(&msg->any.head + 1, hbytes);
703 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
704 msg->any.head.icrc2 = xcrc16;
706 msg->any.head.icrc2 = 0;
708 xcrc32 = hammer2_icrc32(msg->any.buf + HAMMER2_MSGHDR_CRCOFF,
709 HAMMER2_MSGHDR_CRCBYTES);
710 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
711 msg->any.head.icrc1 = xcrc16;
714 * XXX Encrypt the message
718 * Enqueue the message.
720 TAILQ_INSERT_TAIL(&ioq->msgq, msg, entry);
722 iocom->flags &= ~HAMMER2_IOCOMF_WIDLE;
725 * Flush if we know we can write (WREQ not set) and if
726 * sufficient messages have accumulated. Otherwise hold
727 * off to avoid piecemeal system calls.
729 if (iocom->flags & HAMMER2_IOCOMF_WREQ)
731 if (ioq->msgcount < HAMMER2_IOQ_MAXIOVEC / 2)
733 hammer2_iocom_flush(iocom);
737 hammer2_iocom_flush(hammer2_iocom_t *iocom)
739 hammer2_ioq_t *ioq = &iocom->ioq_tx;
743 struct iovec iov[HAMMER2_IOQ_MAXIOVEC];
751 * Pump messages out the connection by building an iovec.
756 TAILQ_FOREACH(msg, &ioq->msgq, entry) {
758 hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) *
761 abytes = msg->aux_size;
766 if (hbytes - hoff > 0) {
767 iov[n].iov_base = (char *)&msg->any.head + hoff;
768 iov[n].iov_len = hbytes - hoff;
769 nmax += hbytes - hoff;
771 if (n == HAMMER2_IOQ_MAXIOVEC)
774 if (abytes - aoff > 0) {
775 assert(msg->aux_data != NULL);
776 iov[n].iov_base = msg->aux_data + aoff;
777 iov[n].iov_len = abytes - aoff;
778 nmax += abytes - aoff;
780 if (n == HAMMER2_IOQ_MAXIOVEC)
788 * Execute the writev() then figure out what happened.
790 nact = writev(iocom->sock_fd, iov, n);
792 if (errno != EINTR &&
793 errno != EINPROGRESS &&
795 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
796 hammer2_iocom_drain(iocom);
798 iocom->flags |= HAMMER2_IOCOMF_WREQ;
803 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
805 iocom->flags |= HAMMER2_IOCOMF_WREQ;
807 while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
808 hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) *
810 abytes = msg->aux_size;
812 if (nact < hbytes - ioq->hbytes) {
816 nact -= hbytes - ioq->hbytes;
817 ioq->hbytes = hbytes;
818 if (nact < abytes - ioq->abytes) {
822 nact -= abytes - ioq->abytes;
824 TAILQ_REMOVE(&ioq->msgq, msg, entry);
829 TAILQ_INSERT_TAIL(&iocom->freeq_aux, msg, entry);
831 TAILQ_INSERT_TAIL(&iocom->freeq, msg, entry);
834 iocom->flags |= HAMMER2_IOCOMF_WIDLE;
835 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
838 iocom->flags |= HAMMER2_IOCOMF_EOF |
839 HAMMER2_IOCOMF_WIDLE;
840 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
845 * Kill pending msgs on ioq_tx and adjust the flags such that no more
846 * write events will occur. We don't kill read msgs because we want
847 * the caller to pull off our contrived terminal error msg to detect
848 * the connection failure.
851 hammer2_iocom_drain(hammer2_iocom_t *iocom)
853 hammer2_ioq_t *ioq = &iocom->ioq_tx;
856 while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
857 TAILQ_REMOVE(&ioq->msgq, msg, entry);
859 hammer2_freemsg(msg);
861 iocom->flags |= HAMMER2_IOCOMF_WIDLE;
862 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
866 * This is a shortcut to the normal hammer2_allocreply() mechanic which
867 * uses the received message to formulate a final reply and error code.
868 * Can be used to issue a final reply for one-way, one-off, or streaming
871 * Replies to one-way messages are a bit of an oxymoron but the feature
872 * is used by the debug (DBG) protocol.
874 * The reply contains no data.
876 * (msg) is eaten up by this function.
879 hammer2_replymsg(hammer2_msg_t *msg, uint16_t error)
881 hammer2_persist_t *pers;
884 assert((msg->any.head.cmd & HAMMER2_MSGF_REPLY) == 0);
886 t16 = msg->any.head.source;
887 msg->any.head.source = msg->any.head.target;
888 msg->any.head.target = t16;
889 msg->any.head.error = error;
890 msg->any.head.cmd |= HAMMER2_MSGF_REPLY;
892 if ((pers = msg->persist) != NULL) {
893 assert(pers->lrep & HAMMER2_MSGF_DELETE);
894 msg->any.head.cmd |= pers->lrep & (HAMMER2_MSGF_CREATE |
895 HAMMER2_MSGF_DELETE);
896 pers->lrep &= ~(HAMMER2_MSGF_CREATE | HAMMER2_MSGF_DELETE);
898 hammer2_ioq_write(msg);