/* * Supporting routines used in common by all the various components of * the SSH system. */ #include #include "ssh.h" #include "sshchan.h" /* ---------------------------------------------------------------------- * Implementation of PacketQueue. */ void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node) { assert(!node->next); assert(!node->prev); node->next = &pqb->end; node->prev = pqb->end.prev; node->next->prev = node; node->prev->next = node; } void pq_base_push_front(PacketQueueBase *pqb, PacketQueueNode *node) { assert(!node->next); assert(!node->prev); node->prev = &pqb->end; node->next = pqb->end.next; node->next->prev = node; node->prev->next = node; } static PktIn *pq_in_get(PacketQueueBase *pqb, int pop) { PacketQueueNode *node = pqb->end.next; if (node == &pqb->end) return NULL; if (pop) { node->next->prev = node->prev; node->prev->next = node->next; node->prev = node->next = NULL; } return FROMFIELD(node, PktIn, qnode); } static PktOut *pq_out_get(PacketQueueBase *pqb, int pop) { PacketQueueNode *node = pqb->end.next; if (node == &pqb->end) return NULL; if (pop) { node->next->prev = node->prev; node->prev->next = node->next; node->prev = node->next = NULL; } return FROMFIELD(node, PktOut, qnode); } void pq_in_init(PktInQueue *pq) { pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; pq->get = pq_in_get; } void pq_out_init(PktOutQueue *pq) { pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end; pq->get = pq_out_get; } void pq_in_clear(PktInQueue *pq) { PktIn *pkt; while ((pkt = pq_pop(pq)) != NULL) ssh_unref_packet(pkt); } void pq_out_clear(PktOutQueue *pq) { PktOut *pkt; while ((pkt = pq_pop(pq)) != NULL) ssh_free_pktout(pkt); } /* * Concatenate the contents of the two queues q1 and q2, and leave the * result in qdest. qdest must be either empty, or one of the input * queues. */ void pq_base_concatenate(PacketQueueBase *qdest, PacketQueueBase *q1, PacketQueueBase *q2) { struct PacketQueueNode *head1, *tail1, *head2, *tail2; /* * Extract the contents from both input queues, and empty them. */ head1 = (q1->end.next == &q1->end ? NULL : q1->end.next); tail1 = (q1->end.prev == &q1->end ? NULL : q1->end.prev); head2 = (q2->end.next == &q2->end ? NULL : q2->end.next); tail2 = (q2->end.prev == &q2->end ? NULL : q2->end.prev); q1->end.next = q1->end.prev = &q1->end; q2->end.next = q2->end.prev = &q2->end; /* * Link the two lists together, handling the case where one or * both is empty. */ if (tail1) tail1->next = head2; else head1 = head2; if (head2) head2->prev = tail1; else tail2 = head1; /* * Check the destination queue is currently empty. (If it was one * of the input queues, then it will be, because we emptied both * of those just a moment ago.) */ assert(qdest->end.next == &qdest->end); assert(qdest->end.prev == &qdest->end); /* * If our concatenated list has anything in it, then put it in * dest. */ if (!head1) { assert(!tail2); } else { assert(tail2); qdest->end.next = head1; qdest->end.prev = tail2; head1->prev = &qdest->end; tail2->next = &qdest->end; } } /* ---------------------------------------------------------------------- * Low-level functions for the packet structures themselves. */ static void ssh_pkt_BinarySink_write(BinarySink *bs, const void *data, size_t len); PktOut *ssh_new_packet(void) { PktOut *pkt = snew(PktOut); BinarySink_INIT(pkt, ssh_pkt_BinarySink_write); pkt->data = NULL; pkt->length = 0; pkt->maxlen = 0; pkt->downstream_id = 0; pkt->additional_log_text = NULL; pkt->qnode.next = pkt->qnode.prev = NULL; return pkt; } static void ssh_pkt_ensure(PktOut *pkt, int length) { if (pkt->maxlen < length) { pkt->maxlen = length + 256; pkt->data = sresize(pkt->data, pkt->maxlen, unsigned char); } } static void ssh_pkt_adddata(PktOut *pkt, const void *data, int len) { pkt->length += len; ssh_pkt_ensure(pkt, pkt->length); memcpy(pkt->data + pkt->length - len, data, len); } static void ssh_pkt_BinarySink_write(BinarySink *bs, const void *data, size_t len) { PktOut *pkt = BinarySink_DOWNCAST(bs, PktOut); ssh_pkt_adddata(pkt, data, len); } void ssh_unref_packet(PktIn *pkt) { if (--pkt->refcount <= 0) sfree(pkt); } void ssh_free_pktout(PktOut *pkt) { sfree(pkt->data); sfree(pkt); }