Commit a3abccdd authored by Olivier Crête's avatar Olivier Crête

pseudotcp: Don't fail when sending over 4GiB of data

Integer comparisons need to take care of rollovers
parent 79866610
...@@ -466,6 +466,10 @@ struct _PseudoTcpSocketPrivate { ...@@ -466,6 +466,10 @@ struct _PseudoTcpSocketPrivate {
gboolean support_wnd_scale; gboolean support_wnd_scale;
}; };
#define LARGER(a,b) (((a) - (b) - 1) < (G_MAXUINT32 >> 1))
#define LARGER_OR_EQUAL(a,b) (((a) - (b)) < (G_MAXUINT32 >> 1))
#define SMALLER(a,b) LARGER ((b),(a))
#define SMALLER_OR_EQUAL(a,b) LARGER_OR_EQUAL ((b),(a))
/* properties */ /* properties */
enum enum
...@@ -1226,13 +1230,14 @@ process(PseudoTcpSocket *self, Segment *seg) ...@@ -1226,13 +1230,14 @@ process(PseudoTcpSocket *self, Segment *seg)
} }
// Update timestamp // Update timestamp
if ((seg->seq <= priv->ts_lastack) && if (SMALLER_OR_EQUAL (seg->seq, priv->ts_lastack) &&
(priv->ts_lastack < seg->seq + seg->len)) { SMALLER (priv->ts_lastack, seg->seq + seg->len)) {
priv->ts_recent = seg->tsval; priv->ts_recent = seg->tsval;
} }
// Check if this is a valuable ack // Check if this is a valuable ack
if ((seg->ack > priv->snd_una) && (seg->ack <= priv->snd_nxt)) { if (LARGER(seg->ack, priv->snd_una) &&
SMALLER_OR_EQUAL(seg->ack, priv->snd_nxt)) {
guint32 nAcked; guint32 nAcked;
guint32 nFree; guint32 nFree;
...@@ -1287,7 +1292,7 @@ process(PseudoTcpSocket *self, Segment *seg) ...@@ -1287,7 +1292,7 @@ process(PseudoTcpSocket *self, Segment *seg)
} }
if (priv->dup_acks >= 3) { if (priv->dup_acks >= 3) {
if (priv->snd_una >= priv->recover) { // NewReno if (LARGER_OR_EQUAL (priv->snd_una, priv->recover)) { // NewReno
guint32 nInFlight = priv->snd_nxt - priv->snd_una; guint32 nInFlight = priv->snd_nxt - priv->snd_una;
// (Fast Retransmit) // (Fast Retransmit)
priv->cwnd = min(priv->ssthresh, nInFlight + priv->mss); priv->cwnd = min(priv->ssthresh, nInFlight + priv->mss);
...@@ -1383,13 +1388,13 @@ process(PseudoTcpSocket *self, Segment *seg) ...@@ -1383,13 +1388,13 @@ process(PseudoTcpSocket *self, Segment *seg)
if (sflags == sfImmediateAck) { if (sflags == sfImmediateAck) {
if (seg->seq > priv->rcv_nxt) { if (seg->seq > priv->rcv_nxt) {
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too new"); DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too new");
} else if (seg->seq + seg->len <= priv->rcv_nxt) { } else if (SMALLER_OR_EQUAL(seg->seq + seg->len, priv->rcv_nxt)) {
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too old"); DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too old");
} }
} }
// Adjust the incoming segment to fit our receive buffer // Adjust the incoming segment to fit our receive buffer
if (seg->seq < priv->rcv_nxt) { if (SMALLER(seg->seq, priv->rcv_nxt)) {
guint32 nAdjust = priv->rcv_nxt - seg->seq; guint32 nAdjust = priv->rcv_nxt - seg->seq;
if (nAdjust < seg->len) { if (nAdjust < seg->len) {
seg->seq += nAdjust; seg->seq += nAdjust;
...@@ -1436,9 +1441,10 @@ process(PseudoTcpSocket *self, Segment *seg) ...@@ -1436,9 +1441,10 @@ process(PseudoTcpSocket *self, Segment *seg)
bNewData = TRUE; bNewData = TRUE;
iter = priv->rlist; iter = priv->rlist;
while (iter && (((RSegment *)iter->data)->seq <= priv->rcv_nxt)) { while (iter &&
SMALLER_OR_EQUAL(((RSegment *)iter->data)->seq, priv->rcv_nxt)) {
RSegment *data = (RSegment *)(iter->data); RSegment *data = (RSegment *)(iter->data);
if (data->seq + data->len > priv->rcv_nxt) { if (LARGER (data->seq + data->len, priv->rcv_nxt)) {
guint32 nAdjust = (data->seq + data->len) - priv->rcv_nxt; guint32 nAdjust = (data->seq + data->len) - priv->rcv_nxt;
sflags = sfImmediateAck; // (Fast Recovery) sflags = sfImmediateAck; // (Fast Recovery)
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Recovered %d bytes (%d -> %d)", DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Recovered %d bytes (%d -> %d)",
...@@ -1460,7 +1466,7 @@ process(PseudoTcpSocket *self, Segment *seg) ...@@ -1460,7 +1466,7 @@ process(PseudoTcpSocket *self, Segment *seg)
rseg->seq = seg->seq; rseg->seq = seg->seq;
rseg->len = seg->len; rseg->len = seg->len;
iter = priv->rlist; iter = priv->rlist;
while (iter && (((RSegment*)iter->data)->seq < rseg->seq)) { while (iter && SMALLER (((RSegment*)iter->data)->seq, rseg->seq)) {
iter = g_list_next (iter); iter = g_list_next (iter);
} }
priv->rlist = g_list_insert_before(priv->rlist, iter, rseg); priv->rlist = g_list_insert_before(priv->rlist, iter, rseg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment