public override void enqueue(DataChunk d) { // todo - this worries me - 2 nested synchronized //logger.LogDebug(" Aspiring to enqueue " + d.ToString()); lock (this) { long now = TimeExtension.CurrentTimeMillis(); d.setTsn(_nearTSN++); d.setGapAck(false); d.setRetryTime(now + getT3() - 1); d.setSentTime(now); SimpleSCTPTimer.setRunnable(run, getT3()); reduceRwnd(d.getDataSize()); //_outbound.put(new Long(d.getTsn()), d); //logger.LogDebug(" DataChunk enqueued " + d.ToString()); // all sorts of things wrong here - being in a synchronized not the least of them Chunk[] toSend = addSackIfNeeded(d); try { send(toSend); //logger.LogDebug("sent, syncing on inFlight... " + d.getTsn()); lock (_inFlight) { _inFlight.Add(d.getTsn(), d); } //logger.LogDebug("added to inFlight... " + d.getTsn()); } catch (SctpPacketFormatException ex) { logger.LogError("badly formatted chunk " + d.ToString()); logger.LogError(ex.ToString()); } catch (EndOfStreamException end) { unexpectedClose(end); logger.LogError(end.ToString()); } catch (IOException ex) { logger.LogError("Can not send chunk " + d.ToString()); logger.LogError(ex.ToString()); } } //logger.LogDebug("leaving enqueue" + d.getTsn()); }
public void run() { ///logger.LogDebug("T1 init timer expired in state " + ta._state.ToString()); if ((ta._state == State.COOKIEECHOED) || (ta._state == State.COOKIEWAIT)) { try { if (ta._state == State.COOKIEWAIT) { ta.sendInit(); } else { // COOKIEECHOED ta.send(ta._stashCookieEcho); } } catch (EndOfStreamException end) { ta.unexpectedClose(end); logger.LogError(end.ToString()); } catch (Exception ex) { logger.LogError("Cant send Init/cookie retry " + retries + " because " + ex.ToString()); } retries++; if (retries < MAX_INIT_RETRANS) { SimpleSCTPTimer.setRunnable(run, ta.getT1()); } } else { //logger.LogDebug("T1 init timer expired with nothing to do"); } }
/* * In instances where its peer endpoint is multi-homed, if an endpoint * receives a SACK that advances its Cumulative TSN Ack Point, then it * should update its cwnd (or cwnds) apportioned to the destination * addresses to which it transmitted the acknowledged data. However, if * * * * Stewart Standards Track [Page 96] * * RFC 4960 Stream Control Transmission Protocol September 2007 * * * the received SACK does not advance the Cumulative TSN Ack Point, the * endpoint MUST NOT adjust the cwnd of any of the destination * addresses. * * Because an endpoint's cwnd is not tied to its Cumulative TSN Ack * Point, as duplicate SACKs come in, even though they may not advance * the Cumulative TSN Ack Point an endpoint can still use them to clock * out new data. That is, the data newly acknowledged by the SACK * diminishes the amount of data now in flight to less than cwnd, and so * the current, unchanged value of cwnd now allows new data to be sent. * On the other hand, the increase of cwnd must be tied to the * Cumulative TSN Ack Point advancement as specified above. Otherwise, * the duplicate SACKs will not only clock out new data, but also will * adversely clock out more new data than what has just left the * network, during a time of possible congestion. * * o When the endpoint does not transmit data on a given transport * address, the cwnd of the transport address should be adjusted to * max(cwnd/2, 4*MTU) per RTO. * */ // timer goes off, public void run() { if (canSend()) { long now = TimeExtension.CurrentTimeMillis(); //logger.LogDebug("retry timer went off at " + now); List <DataChunk> dcs = new List <DataChunk>(); int space = _transpMTU - 12;// room for packet header bool resetTimer = false; lock (_inFlight) { foreach (var kvp in _inFlight) { DataChunk d = kvp.Value; long k = kvp.Key; if (d.getGapAck()) { //logger.LogDebug("skipping gap-acked tsn " + d.getTsn()); continue; } if (d.getRetryTime() <= now) { space -= d.getLength(); //logger.LogDebug("available space in pkt is " + space); if (space <= 0) { resetTimer = true; break; } else { dcs.Add(d); d.setRetryTime(now + getT3() - 1); } } else { //logger.LogDebug("retry not yet due for " + d.ToString()); resetTimer = true; } } } if (dcs.Count != 0) { dcs.Sort(); DataChunk[] da = new DataChunk[dcs.Count]; int i = 0; foreach (DataChunk d in dcs) { da[i++] = d; } resetTimer = true; try { //logger.LogDebug("Sending retry for " + da.Length + " data chunks"); this.send(da); } catch (EndOfStreamException end) { logger.LogWarning("Retry send failed " + end.ToString()); unexpectedClose(end); resetTimer = false; } catch (Exception ex) { logger.LogError("Cant send retry - eek " + ex.ToString()); } } else { //logger.LogDebug("Nothing to do "); } if (resetTimer) { SimpleSCTPTimer.setRunnable(run, getT3()); //logger.LogDebug("Try again in a while " + getT3()); } } }
public override void associate() { sendInit(); SimpleSCTPTimer.setRunnable(new AssocRun(this).run, getT1()); }