Here's the situation: I'm making a proxy (for the moment running on my laptop) which deals with HTTP(S) requests from incoming clients (for the moment only one client, i.e. my Chrome browser on my laptop). It works without troubles, but it is a best effort proxy, i.e. it does not give priority to some types of traffic (streaming over SMTP, for example).
I thought of three classes of priority (minimum:1, medium:2 and maximum:3) and since my traffic has two directions (LAN -> proxy -> WAN
and WAN -> proxy -> LAN
), I thought about six queues of priority like these (the FIFO nature of queue won't cause starvation of packets):
// LAN -> proxy -> WAN, from max to min priority
queue queue_to_remote_3;
queue queue_to_remote_2;
queue queue_to_remote_1;
// WAN -> proxy -> LAN, from max to min priority
queue queue_to_local_3;
queue queue_to_local_2;
queue queue_to_local_1;
This is the pseudocode (C-like) of the algorithm I made dealing with incoming packets from both LAN and WAN: I'll post just the part dealing LAN -> proxy -> WAN
, since WAN -> proxy -> LAN
has the same reasoning, but instead of queue_to_remote_X
it uses queue_to_local_X
:
void algoQueues(packet pkt, int direction, int priority) {
if (direction == TO_REMOTE) {
switch (priority) {
case 1: { // MAXIMUM priority
// if queue1 is empty, just let it pass
if (queue_to_remote_1.empty()) {
letPass(pkt);
}
// if queue1 is not empty, push the arrived pkt and
// pop another pkt from the queue to let it pass
else {
queue_to_remote1.push(pkt);
packet new_pkt = queue_to_remote1.pop();
letPass(new_pkt);
}
break;
}
case 2: { // MEDIUM priority
// first check if queue1 has pkts to send
if (queue_to_remote_1.empty()) {
// if queue1 is empty, then check queue2
if (queue_to_remote_2.empty()) {
// if queue2 is empty too, just let the packet pass
letPass(pkt);
}
// if queue1 is empty and queue2 is not empty,
// push the new arrived pkt in queue2 and send
// a queued pkt from queue2
else {
queue_to_remote_2.push(pkt);
packet new_pkt = queue_to_remote_2.pop();
letPass(new_pkt);
}
}
// if queue1 is not empty, I must queue the new arrived pkt
// in queue 2 and send a queued pkt from queue1
else {
queue_to_remote_2.push(pkt);
packet new_pkt = queue_to_remote_1.pop();
letPass(new_pkt);
}
break;
}
case 3: { // MINIMUM priority
// first check if queue1 has pkts to send
if (queue_to_remote_1.empty()) {
// if queue1 is empty, then check queue2
if (queue_to_remote_2.empty()) {
// if queue3 is empty, just let it pass
if (queue_to_remote_3.empty()) {
letPass(pkt);
}
// if queue3 is not empty, push the arrived pkt
// in queue3 and pop another pkt from the
// same queue to let it pass
else {
queue_to_remote_3.push(pkt);
packet new_pkt = queue_to_remote_3.pop();
letPass(new_pkt);
}
}
// if queue2 is not empty and queue1 is empty, push the
// arrived pkt in queue3, get a pkt from queue2 and send it
else {
queue_to_remote_3.push(pkt);
packet new_pkt = queue_to_remote_2.pop();
letPass(new_pkt);
}
}
// if queue1 is not empty, queue the pkt in queue3
// and send a pkt from queue1
else {
queue_to_remote_3.push(pkt);
packet new_pkt = queue_to_remote_1.pop();
letPass(new_pkt);
}
break;
}
default: {
printf("To remote: unknown priority, strange...\n");
exit(EXIT_FAILURE);
}
}
}
else if (direction == TO_LOCAL) {
/* ... */
}
}
A smart observer might object: "when do you insert the first packet???", and that is my issue; the first time this algorithm is called, all queues are empty, so every packet will just pass!
I can't push the first packet of any priority in its queue and break from switch
statement in order to unlock all others if
s, it sounds stupid: is my reasoning (and thus my algorithm) wrong, or am I using the wrong data structure?