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, hammer2_ioq_t *ioq)
54 while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
55 TAILQ_REMOVE(&ioq->msgq, msg, entry);
56 hammer2_iocom_freemsg(iocom, msg);
58 if ((msg = ioq->msg) != NULL) {
60 hammer2_iocom_freemsg(iocom, msg);
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 fcntl(sock_fd, F_SETFL, O_NONBLOCK);
83 /* if line buffered our single fgets() should be fine */
85 fcntl(alt_fd, F_SETFL, O_NONBLOCK);
90 hammer2_iocom_done(hammer2_iocom_t *iocom)
95 hammer2_ioq_done(iocom, &iocom->ioq_rx);
96 hammer2_ioq_done(iocom, &iocom->ioq_tx);
97 if ((msg = TAILQ_FIRST(&iocom->freeq)) != NULL) {
98 TAILQ_REMOVE(&iocom->freeq, msg, entry);
101 if ((msg = TAILQ_FIRST(&iocom->freeq_aux)) != NULL) {
102 TAILQ_REMOVE(&iocom->freeq_aux, msg, entry);
104 msg->aux_data = NULL;
110 hammer2_iocom_allocmsg(hammer2_iocom_t *iocom, uint32_t cmd, int aux_size)
116 aux_size = (aux_size + HAMMER2_MSG_ALIGNMASK) &
117 ~HAMMER2_MSG_ALIGNMASK;
118 if ((msg = TAILQ_FIRST(&iocom->freeq_aux)) != NULL)
119 TAILQ_REMOVE(&iocom->freeq_aux, msg, entry);
121 if ((msg = TAILQ_FIRST(&iocom->freeq)) != NULL)
122 TAILQ_REMOVE(&iocom->freeq, msg, entry);
125 msg = malloc(sizeof(*msg));
126 msg->aux_data = NULL;
129 if (msg->aux_size != aux_size) {
132 msg->aux_data = NULL;
136 msg->aux_data = malloc(aux_size);
137 msg->aux_size = aux_size;
141 hbytes = (cmd & HAMMER2_MSGF_SIZE) * HAMMER2_MSG_ALIGN;
142 bzero(&msg->any.head, hbytes);
143 msg->any.head.cmd = cmd;
149 hammer2_iocom_reallocmsg(hammer2_iocom_t *iocom __unused, hammer2_msg_t *msg,
152 aux_size = (aux_size + HAMMER2_MSG_ALIGNMASK) & ~HAMMER2_MSG_ALIGNMASK;
153 if (aux_size && msg->aux_size != aux_size) {
156 msg->aux_data = NULL;
158 msg->aux_data = malloc(aux_size);
159 msg->aux_size = aux_size;
165 hammer2_iocom_freemsg(hammer2_iocom_t *iocom, hammer2_msg_t *msg)
168 TAILQ_INSERT_TAIL(&iocom->freeq_aux, msg, entry);
170 TAILQ_INSERT_TAIL(&iocom->freeq, msg, entry);
174 * I/O core loop for an iocom.
177 hammer2_iocom_core(hammer2_iocom_t *iocom,
178 void (*recvmsg_func)(hammer2_iocom_t *),
179 void (*sendmsg_func)(hammer2_iocom_t *),
180 void (*altmsg_func)(hammer2_iocom_t *))
182 struct pollfd fds[2];
185 iocom->recvmsg_callback = recvmsg_func;
186 iocom->sendmsg_callback = sendmsg_func;
187 iocom->altmsg_callback = altmsg_func;
189 while ((iocom->flags & HAMMER2_IOCOMF_EOF) == 0) {
190 fds[0].fd = iocom->sock_fd;
194 if (iocom->flags & HAMMER2_IOCOMF_RREQ)
195 fds[0].events |= POLLIN;
198 if ((iocom->flags & HAMMER2_IOCOMF_WIDLE) == 0) {
199 if (iocom->flags & HAMMER2_IOCOMF_WREQ)
200 fds[0].events |= POLLOUT;
205 if (iocom->alt_fd >= 0) {
206 fds[1].fd = iocom->alt_fd;
207 fds[1].events |= POLLIN;
209 poll(fds, 2, timeout);
211 poll(fds, 1, timeout);
213 if ((fds[0].revents & POLLIN) ||
214 (iocom->flags & HAMMER2_IOCOMF_RREQ) == 0) {
215 iocom->recvmsg_callback(iocom);
217 if ((iocom->flags & HAMMER2_IOCOMF_WIDLE) == 0) {
218 if ((fds[0].revents & POLLOUT) ||
219 (iocom->flags & HAMMER2_IOCOMF_WREQ) == 0) {
220 iocom->sendmsg_callback(iocom);
223 if (iocom->alt_fd >= 0 && (fds[1].revents & POLLIN))
224 iocom->altmsg_callback(iocom);
229 * Read the next ready message from the ioq, issuing I/O if needed.
230 * Caller should retry on a read-event when NULL is returned.
232 * If an error occurs during reception a HAMMER2_LNK_ERROR msg will
233 * be returned (and the caller must not call us again after that).
236 hammer2_ioq_read(hammer2_iocom_t *iocom)
238 hammer2_ioq_t *ioq = &iocom->ioq_rx;
240 hammer2_msg_hdr_t *head;
249 * If a message is already pending we can just remove and
252 if ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
253 TAILQ_REMOVE(&ioq->msgq, msg, entry);
258 * Message read in-progress (msg is NULL at the moment). We don't
259 * allocate a msg until we have its core header.
261 bytes = ioq->fifo_end - ioq->fifo_beg;
262 nmax = sizeof(iocom->rxbuf) - ioq->fifo_end;
266 case HAMMER2_MSGQ_STATE_HEADER1:
268 * Load the primary header, fail on any non-trivial read
269 * error or on EOF. Since the primary header is the same
270 * size is the message alignment it will never straddle
271 * the end of the buffer.
273 if (bytes < (int)sizeof(msg->any.head)) {
274 n = read(iocom->sock_fd,
275 iocom->rxbuf + ioq->fifo_end,
279 ioq->error = HAMMER2_IOQ_ERROR_EOF;
282 if (errno != EINTR &&
283 errno != EINPROGRESS &&
285 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
297 * Insufficient data accumulated (msg is NULL, caller will
301 if (bytes < (int)sizeof(msg->any.head))
305 head = (void *)(iocom->rxbuf + ioq->fifo_beg);
308 * XXX Decrypt the core header
312 * Check and fixup the core header. Note that the icrc
313 * has to be calculated before any fixups, but the crc
314 * fields in the msg may have to be swapped like everything
317 if (head->magic != HAMMER2_MSGHDR_MAGIC &&
318 head->magic != HAMMER2_MSGHDR_MAGIC_REV) {
319 ioq->error = HAMMER2_IOQ_ERROR_SYNC;
323 xcrc32 = hammer2_icrc32((char *)head + HAMMER2_MSGHDR_CRCOFF,
324 HAMMER2_MSGHDR_CRCBYTES);
325 if (head->magic == HAMMER2_MSGHDR_MAGIC_REV) {
326 hammer2_bswap_head(head);
327 flags |= HAMMER2_MSGX_BSWAPPED;
329 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
330 if (xcrc16 != head->icrc1) {
331 ioq->error = HAMMER2_IOQ_ERROR_HCRC;
336 * Calculate the full header size and aux data size
338 ioq->hbytes = (head->cmd & HAMMER2_MSGF_SIZE) *
340 ioq->abytes = head->aux_bytes * HAMMER2_MSG_ALIGN;
341 if (ioq->hbytes < (int)sizeof(msg->any.head) ||
342 ioq->hbytes > (int)sizeof(msg->any) ||
343 ioq->abytes > HAMMER2_MSGAUX_MAX) {
344 ioq->error = HAMMER2_IOQ_ERROR_FIELD;
349 * Finally allocate the message and copy the core header
350 * to the embedded extended header.
353 if ((msg = TAILQ_FIRST(&iocom->freeq_aux)) != NULL) {
354 TAILQ_REMOVE(&iocom->freeq_aux, msg, entry);
356 msg = malloc(sizeof(*msg));
357 msg->aux_data = NULL;
360 if (msg->aux_size != ioq->abytes) {
363 msg->aux_data = NULL;
365 msg->aux_data = malloc(ioq->abytes);
366 /* msg->aux_size = ioq->abytes; */
369 if ((msg = TAILQ_FIRST(&iocom->freeq)) != NULL) {
370 TAILQ_REMOVE(&iocom->freeq, msg, entry);
372 msg = malloc(sizeof(*msg));
373 msg->aux_data = NULL;
374 /* msg->aux_size = 0; */
377 msg->aux_size = 0; /* data copied so far */
382 * We are either done or we fall-through
384 if (ioq->hbytes == sizeof(msg->any.head) && ioq->abytes == 0) {
385 bcopy(head, &msg->any.head, sizeof(msg->any.head));
386 ioq->fifo_beg += ioq->hbytes;
391 * Fall through to the next state. Make sure that the
392 * extended header does not straddle the end of the buffer.
393 * We still want to issue larger reads into our buffer,
394 * book-keeping is easier if we don't bcopy() yet.
396 if (bytes + nmax < ioq->hbytes) {
397 bcopy(iocom->rxbuf + ioq->fifo_beg, iocom->rxbuf,
400 ioq->fifo_end = bytes;
401 nmax = sizeof(iocom->rxbuf) - ioq->fifo_end;
403 ioq->state = HAMMER2_MSGQ_STATE_HEADER2;
405 case HAMMER2_MSGQ_STATE_HEADER2:
407 * Fill out the extended header.
410 if (bytes < ioq->hbytes) {
411 n = read(iocom->sock_fd,
412 msg->any.buf + ioq->fifo_end,
416 ioq->error = HAMMER2_IOQ_ERROR_EOF;
419 if (errno != EINTR &&
420 errno != EINPROGRESS &&
422 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
434 * Insufficient data accumulated (set msg NULL so caller will
437 if (bytes < ioq->hbytes) {
443 * XXX Decrypt the extended header
445 head = (void *)(iocom->rxbuf + ioq->fifo_beg);
448 * Check the crc on the extended header
450 if (ioq->hbytes > (int)sizeof(hammer2_msg_hdr_t)) {
451 xcrc32 = hammer2_icrc32(head + 1,
452 ioq->hbytes - sizeof(*head));
453 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
454 if (head->icrc2 != xcrc16) {
455 ioq->error = HAMMER2_IOQ_ERROR_XCRC;
461 * Copy the extended header into the msg and adjust the
464 bcopy(head, &msg->any, ioq->hbytes);
467 * We are either done or we fall-through.
469 if (ioq->abytes == 0) {
470 ioq->fifo_beg += ioq->hbytes;
475 * Must adjust nmax and bytes (and the state) when falling
478 ioq->fifo_beg += ioq->hbytes;
480 bytes -= ioq->hbytes;
481 ioq->state = HAMMER2_MSGQ_STATE_AUXDATA1;
483 case HAMMER2_MSGQ_STATE_AUXDATA1:
485 * Copy the partial or complete payload from remaining
486 * bytes in the FIFO. We have to fall-through either
487 * way so we can check the crc.
489 assert(msg->aux_size == 0);
490 if (bytes >= ioq->abytes) {
491 bcopy(iocom->rxbuf + ioq->fifo_beg, msg->aux_data,
493 msg->aux_size = ioq->abytes;
494 ioq->fifo_beg += ioq->abytes;
495 bytes -= ioq->abytes;
497 bcopy(iocom->rxbuf + ioq->fifo_beg, msg->aux_data,
499 msg->aux_size = bytes;
500 ioq->fifo_beg += bytes;
503 ioq->state = HAMMER2_MSGQ_STATE_AUXDATA2;
505 case HAMMER2_MSGQ_STATE_AUXDATA2:
507 * Read the remainder of the payload directly into the
508 * msg->aux_data buffer.
511 if (msg->aux_size < ioq->abytes) {
513 n = read(iocom->sock_fd,
514 msg->aux_data + msg->aux_size,
515 ioq->abytes - msg->aux_size);
518 ioq->error = HAMMER2_IOQ_ERROR_EOF;
521 if (errno != EINTR &&
522 errno != EINPROGRESS &&
524 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
534 * Insufficient data accumulated (set msg NULL so caller will
537 if (msg->aux_size < ioq->abytes) {
541 assert(msg->aux_size == ioq->abytes);
544 * XXX Decrypt the data
548 * Check aux_icrc, then we are done.
550 xcrc32 = hammer2_icrc32(msg->aux_data, msg->aux_size);
551 if (xcrc32 != msg->any.head.aux_icrc) {
552 ioq->error = HAMMER2_IOQ_ERROR_ACRC;
556 case HAMMER2_MSGQ_STATE_ERROR:
559 * We don't double-return errors, the caller should not
560 * have called us again after getting an error msg.
567 * Handle error, RREQ, or completion
569 * NOTE: nmax and bytes are invalid at this point, we don't bother
570 * to update them when breaking out.
574 * An unrecoverable error occured during processing,
575 * return a special error message. Try to leave the
576 * ioq state alone for post-mortem debugging.
578 * Link error messages are returned as one-way messages,
579 * so no flags get set. Source and target is 0 (link-level),
580 * msgid is 0 (link-level). All we really need to do is
581 * set up magic, cmd, and error.
584 if ((msg = TAILQ_FIRST(&iocom->freeq)) != NULL) {
585 TAILQ_REMOVE(&iocom->freeq, msg, entry);
587 msg = malloc(sizeof(*msg));
588 msg->aux_data = NULL;
591 assert(ioq->msg == NULL);
593 assert(ioq->msg == msg);
598 msg->aux_data = NULL;
601 bzero(&msg->any.head, sizeof(msg->any.head));
602 msg->any.head.magic = HAMMER2_MSGHDR_MAGIC;
603 msg->any.head.cmd = HAMMER2_LNK_ERROR;
604 msg->any.head.error = ioq->error;
605 ioq->state = HAMMER2_MSGQ_STATE_ERROR;
606 iocom->flags |= HAMMER2_IOCOMF_EOF;
607 } else if (msg == NULL) {
609 * Insufficient data received to finish building the message,
610 * set RREQ and return NULL.
612 * Leave ioq->msg intact.
613 * Leave the FIFO intact.
615 iocom->flags |= HAMMER2_IOCOMF_RREQ;
620 * Return msg, clear the FIFO if it is now empty.
621 * Flag RREQ if the caller needs to wait for a read-event
624 * The fifo has already been advanced past the message.
625 * Trivially reset the FIFO indices if possible.
627 if (ioq->fifo_beg == ioq->fifo_end) {
628 iocom->flags |= HAMMER2_IOCOMF_RREQ;
632 iocom->flags &= ~HAMMER2_IOCOMF_RREQ;
634 ioq->state = HAMMER2_MSGQ_STATE_HEADER1;
641 * Calculate the header and data crc's and write a low-level message to
642 * the connection. If aux_icrc is non-zero the aux_data crc is already
643 * assumed to have been set.
645 * A non-NULL msg is added to the queue but not necessarily flushed.
646 * Calling this function with msg == NULL will get a flush going.
649 hammer2_ioq_write(hammer2_iocom_t *iocom, hammer2_msg_t *msg)
651 hammer2_ioq_t *ioq = &iocom->ioq_tx;
660 struct iovec iov[HAMMER2_IOQ_MAXIOVEC];
665 TAILQ_INSERT_TAIL(&ioq->msgq, msg, entry);
668 hammer2_ioq_write_drain(iocom);
674 * Finish populating the msg fields
676 msg->any.head.magic = HAMMER2_MSGHDR_MAGIC;
677 msg->any.head.salt = (random() << 8) | (ioq->seq & 255);
681 * Calculate aux_icrc if 0, calculate icrc2, and finally
684 if (msg->aux_size && msg->any.head.aux_icrc == 0) {
685 assert((msg->aux_size & HAMMER2_MSG_ALIGNMASK) == 0);
686 xcrc32 = hammer2_icrc32(msg->aux_data, msg->aux_size);
687 msg->any.head.aux_icrc = xcrc32;
689 msg->any.head.aux_bytes = msg->aux_size / HAMMER2_MSG_ALIGN;
690 assert((msg->aux_size & HAMMER2_MSG_ALIGNMASK) == 0);
692 if ((msg->any.head.cmd & HAMMER2_MSGF_SIZE) >
693 sizeof(msg->any.head) / HAMMER2_MSG_ALIGN) {
694 hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) *
696 hbytes -= sizeof(msg->any.head);
697 xcrc32 = hammer2_icrc32(&msg->any.head + 1, hbytes);
698 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
699 msg->any.head.icrc2 = xcrc16;
701 msg->any.head.icrc2 = 0;
703 xcrc32 = hammer2_icrc32(msg->any.buf + HAMMER2_MSGHDR_CRCOFF,
704 HAMMER2_MSGHDR_CRCBYTES);
705 xcrc16 = (uint16_t)xcrc32 ^ (uint16_t)(xcrc32 >> 16);
706 msg->any.head.icrc1 = xcrc16;
709 * XXX Encrypt the message
713 * Enqueue the message, stop now if we already know that
716 TAILQ_INSERT_TAIL(&ioq->msgq, msg, entry);
718 iocom->flags &= ~HAMMER2_IOCOMF_WIDLE;
719 if (iocom->flags & HAMMER2_IOCOMF_WREQ)
723 * Flush if we can aggregate several msgs, otherwise
724 * we will wait for the global flush (msg == NULL).
726 if (ioq->msgcount < HAMMER2_IOQ_MAXIOVEC / 2)
728 } else if (iocom->flags &= HAMMER2_IOCOMF_WIDLE) {
730 * Nothing to do if WIDLE is set.
732 assert(TAILQ_FIRST(&ioq->msgq) == NULL);
737 * Pump messages out the connection by building an iovec.
742 TAILQ_FOREACH(msg, &ioq->msgq, entry) {
744 hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) *
747 abytes = msg->aux_size;
752 if (hbytes - hoff > 0) {
753 iov[n].iov_base = (char *)&msg->any.head + hoff;
754 iov[n].iov_len = hbytes - hoff;
755 nmax += hbytes - hoff;
757 if (n == HAMMER2_IOQ_MAXIOVEC)
760 if (abytes - aoff > 0) {
761 assert(msg->aux_data != NULL);
762 iov[n].iov_base = msg->aux_data + aoff;
763 iov[n].iov_len = abytes - aoff;
764 nmax += abytes - aoff;
766 if (n == HAMMER2_IOQ_MAXIOVEC)
774 * Execute the writev() then figure out what happened.
776 nact = writev(iocom->sock_fd, iov, n);
778 if (errno != EINTR &&
779 errno != EINPROGRESS &&
781 ioq->error = HAMMER2_IOQ_ERROR_SOCK;
782 hammer2_ioq_write_drain(iocom);
784 iocom->flags |= HAMMER2_IOCOMF_WREQ;
789 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
791 iocom->flags |= HAMMER2_IOCOMF_WREQ;
793 while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
794 hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) *
796 abytes = msg->aux_size;
798 if (nact < hbytes - ioq->hbytes) {
802 nact -= hbytes - ioq->hbytes;
803 ioq->hbytes = hbytes;
804 if (nact < abytes - ioq->abytes) {
808 nact -= abytes - ioq->abytes;
810 TAILQ_REMOVE(&ioq->msgq, msg, entry);
815 TAILQ_INSERT_TAIL(&iocom->freeq_aux, msg, entry);
817 TAILQ_INSERT_TAIL(&iocom->freeq, msg, entry);
820 iocom->flags |= HAMMER2_IOCOMF_WIDLE;
821 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
824 iocom->flags |= HAMMER2_IOCOMF_EOF |
825 HAMMER2_IOCOMF_WIDLE;
826 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
831 * Kill pending msgs on ioq_tx and adjust the flags such that no more
832 * write events will occur. We don't kill read msgs because we want
833 * the caller to pull off our contrived terminal error msg to detect
834 * the connection failure.
837 hammer2_ioq_write_drain(hammer2_iocom_t *iocom)
839 hammer2_ioq_t *ioq = &iocom->ioq_tx;
842 while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) {
843 TAILQ_REMOVE(&ioq->msgq, msg, entry);
845 hammer2_iocom_freemsg(iocom, msg);
847 iocom->flags |= HAMMER2_IOCOMF_WIDLE;
848 iocom->flags &= ~HAMMER2_IOCOMF_WREQ;
852 * Reply to a message after setting various fields appropriately.
853 * This function will swap (source) and (target) and enqueue the
854 * message for transmission.
857 hammer2_ioq_reply(hammer2_iocom_t *iocom, hammer2_msg_t *msg)
861 t16 = msg->any.head.source;
862 msg->any.head.source = msg->any.head.target;
863 msg->any.head.target = t16;
864 msg->any.head.cmd ^= HAMMER2_MSGF_REPLY;
865 hammer2_ioq_write(iocom, msg);
869 hammer2_ioq_reply_term(hammer2_iocom_t *iocom, hammer2_msg_t *msg,
872 if (msg->any.head.cmd & HAMMER2_MSGF_CREATE) {
873 msg->any.head.cmd |= HAMMER2_MSGF_CREATE | HAMMER2_MSGF_DELETE;
874 msg->any.head.error = error;
875 hammer2_ioq_reply(iocom, msg);