Utility routines for iterating over a packet queue.

I haven't needed these until now, but I'm about to need to inspect the
entire contents of a packet queue before deciding whether to process
the first item on it.

I've changed the single 'vtable method' in packet queues from get(),
which returned the head of the queue and optionally popped it, to
after() which does the same bug returns the item after a specified
tree node. So if you pass the special end node to after(), then it
behaves like get(), but now you can also use it to retrieve the
successor of a packet.

(Orthogonality says that you can also _pop_ the successor of a packet
by calling after() with prev != pq.end and pop == TRUE. I don't have a
use for that one yet.)
This commit is contained in:
Simon Tatham 2018-10-06 18:42:08 +01:00
Родитель 0bbe87f11e
Коммит 36caf03a5b
2 изменённых файлов: 23 добавлений и 18 удалений

27
ssh.h
Просмотреть файл

@ -90,12 +90,12 @@ typedef struct PacketQueueBase {
typedef struct PktInQueue {
PacketQueueBase pqb;
PktIn *(*get)(PacketQueueBase *, int pop);
PktIn *(*after)(PacketQueueBase *, PacketQueueNode *prev, int pop);
} PktInQueue;
typedef struct PktOutQueue {
PacketQueueBase pqb;
PktOut *(*get)(PacketQueueBase *, int pop);
PktOut *(*after)(PacketQueueBase *, PacketQueueNode *prev, int pop);
} PktOutQueue;
void pq_base_push(PacketQueueBase *pqb, PacketQueueNode *node);
@ -108,21 +108,24 @@ void pq_out_init(PktOutQueue *pq);
void pq_in_clear(PktInQueue *pq);
void pq_out_clear(PktOutQueue *pq);
#define pq_push(pq, pkt) \
TYPECHECK((pq)->get(&(pq)->pqb, FALSE) == pkt, \
#define pq_push(pq, pkt) \
TYPECHECK((pq)->after(&(pq)->pqb, NULL, FALSE) == pkt, \
pq_base_push(&(pq)->pqb, &(pkt)->qnode))
#define pq_push_front(pq, pkt) \
TYPECHECK((pq)->get(&(pq)->pqb, FALSE) == pkt, \
TYPECHECK((pq)->after(&(pq)->pqb, NULL, FALSE) == pkt, \
pq_base_push_front(&(pq)->pqb, &(pkt)->qnode))
#define pq_peek(pq) ((pq)->get(&(pq)->pqb, FALSE))
#define pq_pop(pq) ((pq)->get(&(pq)->pqb, TRUE))
#define pq_concatenate(dst, q1, q2) \
TYPECHECK((q1)->get(&(q1)->pqb, FALSE) == \
(dst)->get(&(dst)->pqb, FALSE) && \
(q2)->get(&(q2)->pqb, FALSE) == \
(dst)->get(&(dst)->pqb, FALSE), \
#define pq_peek(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, FALSE))
#define pq_pop(pq) ((pq)->after(&(pq)->pqb, &(pq)->pqb.end, TRUE))
#define pq_concatenate(dst, q1, q2) \
TYPECHECK((q1)->after(&(q1)->pqb, NULL, FALSE) == \
(dst)->after(&(dst)->pqb, NULL, FALSE) && \
(q2)->after(&(q2)->pqb, NULL, FALSE) == \
(dst)->after(&(dst)->pqb, NULL, FALSE), \
pq_base_concatenate(&(dst)->pqb, &(q1)->pqb, &(q2)->pqb))
#define pq_first(pq) pq_peek(pq)
#define pq_next(pq, pkt) ((pq)->after(&(pq)->pqb, &(pkt)->qnode, FALSE))
/*
* Packet type contexts, so that ssh2_pkt_type can correctly decode
* the ambiguous type numbers back into the correct type strings.

Просмотреть файл

@ -71,9 +71,10 @@ static IdempotentCallback ic_pktin_free = {
pktin_free_queue_callback, NULL, FALSE
};
static PktIn *pq_in_get(PacketQueueBase *pqb, int pop)
static PktIn *pq_in_after(PacketQueueBase *pqb,
PacketQueueNode *prev, int pop)
{
PacketQueueNode *node = pqb->end.next;
PacketQueueNode *node = prev->next;
if (node == &pqb->end)
return NULL;
@ -92,9 +93,10 @@ static PktIn *pq_in_get(PacketQueueBase *pqb, int pop)
return container_of(node, PktIn, qnode);
}
static PktOut *pq_out_get(PacketQueueBase *pqb, int pop)
static PktOut *pq_out_after(PacketQueueBase *pqb,
PacketQueueNode *prev, int pop)
{
PacketQueueNode *node = pqb->end.next;
PacketQueueNode *node = prev->next;
if (node == &pqb->end)
return NULL;
@ -111,14 +113,14 @@ void pq_in_init(PktInQueue *pq)
{
pq->pqb.ic = NULL;
pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end;
pq->get = pq_in_get;
pq->after = pq_in_after;
}
void pq_out_init(PktOutQueue *pq)
{
pq->pqb.ic = NULL;
pq->pqb.end.next = pq->pqb.end.prev = &pq->pqb.end;
pq->get = pq_out_get;
pq->after = pq_out_after;
}
void pq_in_clear(PktInQueue *pq)