kcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.en.md +235 -0
- data/README.md +221 -0
- data/ext/kcp/extconf.rb +9 -0
- data/ext/kcp/ikcp.c +1423 -0
- data/ext/kcp/ikcp.h +452 -0
- data/ext/kcp/kcp_native.c +137 -0
- data/lib/kcp/version.rb +5 -0
- data/lib/kcp.rb +76 -0
- metadata +65 -0
data/ext/kcp/ikcp.c
ADDED
|
@@ -0,0 +1,1423 @@
|
|
|
1
|
+
//=====================================================================
|
|
2
|
+
//
|
|
3
|
+
// KCP - A Better ARQ Protocol Implementation
|
|
4
|
+
// skywind3000 (at) gmail.com, 2010-2011
|
|
5
|
+
//
|
|
6
|
+
// Features:
|
|
7
|
+
// + Average RTT reduce 30% - 40% vs traditional ARQ like tcp.
|
|
8
|
+
// + Maximum RTT reduce three times vs tcp.
|
|
9
|
+
// + Lightweight, distributed as a single source file.
|
|
10
|
+
//
|
|
11
|
+
//=====================================================================
|
|
12
|
+
#include "ikcp.h"
|
|
13
|
+
|
|
14
|
+
#include <stddef.h>
|
|
15
|
+
#include <stdlib.h>
|
|
16
|
+
#include <string.h>
|
|
17
|
+
#include <stdarg.h>
|
|
18
|
+
#include <stdio.h>
|
|
19
|
+
|
|
20
|
+
#define IKCP_FASTACK_CONSERVE
|
|
21
|
+
|
|
22
|
+
//=====================================================================
|
|
23
|
+
// KCP BASIC
|
|
24
|
+
//=====================================================================
|
|
25
|
+
const IUINT32 IKCP_RTO_NDL = 30; // no delay min rto
|
|
26
|
+
const IUINT32 IKCP_RTO_MIN = 100; // normal min rto
|
|
27
|
+
const IUINT32 IKCP_RTO_DEF = 200;
|
|
28
|
+
const IUINT32 IKCP_RTO_MAX = 60000;
|
|
29
|
+
const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data
|
|
30
|
+
const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack
|
|
31
|
+
const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask)
|
|
32
|
+
const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell)
|
|
33
|
+
const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK
|
|
34
|
+
const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS
|
|
35
|
+
const IUINT32 IKCP_WND_SND = 32;
|
|
36
|
+
const IUINT32 IKCP_WND_RCV = 128; // must >= max fragment size
|
|
37
|
+
const IUINT32 IKCP_MTU_DEF = 1400;
|
|
38
|
+
const IUINT32 IKCP_ACK_FAST = 3;
|
|
39
|
+
const IUINT32 IKCP_INTERVAL = 100;
|
|
40
|
+
const IUINT32 IKCP_OVERHEAD = 24;
|
|
41
|
+
const IUINT32 IKCP_DEADLINK = 20;
|
|
42
|
+
const IUINT32 IKCP_THRESH_INIT = 2;
|
|
43
|
+
const IUINT32 IKCP_THRESH_MIN = 2;
|
|
44
|
+
const IUINT32 IKCP_PROBE_INIT = 5000; // 7 secs to probe window size
|
|
45
|
+
const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window
|
|
46
|
+
const IUINT32 IKCP_FASTACK_LIMIT = 5; // max times to trigger fastack
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
//---------------------------------------------------------------------
|
|
50
|
+
// encode / decode
|
|
51
|
+
//---------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
/* encode 8 bits unsigned int */
|
|
54
|
+
static inline char *ikcp_encode8u(char *p, unsigned char c)
|
|
55
|
+
{
|
|
56
|
+
*(unsigned char*)p++ = c;
|
|
57
|
+
return p;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* decode 8 bits unsigned int */
|
|
61
|
+
static inline const char *ikcp_decode8u(const char *p, unsigned char *c)
|
|
62
|
+
{
|
|
63
|
+
*c = *(unsigned char*)p++;
|
|
64
|
+
return p;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* encode 16 bits unsigned int (lsb) */
|
|
68
|
+
static inline char *ikcp_encode16u(char *p, unsigned short w)
|
|
69
|
+
{
|
|
70
|
+
#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN
|
|
71
|
+
*(unsigned char*)(p + 0) = (w & 255);
|
|
72
|
+
*(unsigned char*)(p + 1) = (w >> 8);
|
|
73
|
+
#else
|
|
74
|
+
memcpy(p, &w, 2);
|
|
75
|
+
#endif
|
|
76
|
+
p += 2;
|
|
77
|
+
return p;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* decode 16 bits unsigned int (lsb) */
|
|
81
|
+
static inline const char *ikcp_decode16u(const char *p, unsigned short *w)
|
|
82
|
+
{
|
|
83
|
+
#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN
|
|
84
|
+
*w = *(const unsigned char*)(p + 1);
|
|
85
|
+
*w = *(const unsigned char*)(p + 0) + (*w << 8);
|
|
86
|
+
#else
|
|
87
|
+
memcpy(w, p, 2);
|
|
88
|
+
#endif
|
|
89
|
+
p += 2;
|
|
90
|
+
return p;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* encode 32 bits unsigned int (lsb) */
|
|
94
|
+
static inline char *ikcp_encode32u(char *p, IUINT32 l)
|
|
95
|
+
{
|
|
96
|
+
#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN
|
|
97
|
+
*(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff);
|
|
98
|
+
*(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff);
|
|
99
|
+
*(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff);
|
|
100
|
+
*(unsigned char*)(p + 3) = (unsigned char)((l >> 24) & 0xff);
|
|
101
|
+
#else
|
|
102
|
+
memcpy(p, &l, 4);
|
|
103
|
+
#endif
|
|
104
|
+
p += 4;
|
|
105
|
+
return p;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* decode 32 bits unsigned int (lsb) */
|
|
109
|
+
static inline const char *ikcp_decode32u(const char *p, IUINT32 *l)
|
|
110
|
+
{
|
|
111
|
+
#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN
|
|
112
|
+
*l = *(const unsigned char*)(p + 3);
|
|
113
|
+
*l = *(const unsigned char*)(p + 2) + (*l << 8);
|
|
114
|
+
*l = *(const unsigned char*)(p + 1) + (*l << 8);
|
|
115
|
+
*l = *(const unsigned char*)(p + 0) + (*l << 8);
|
|
116
|
+
#else
|
|
117
|
+
memcpy(l, p, 4);
|
|
118
|
+
#endif
|
|
119
|
+
p += 4;
|
|
120
|
+
return p;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static inline IUINT32 _imin_(IUINT32 a, IUINT32 b) {
|
|
124
|
+
return a <= b ? a : b;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static inline IUINT32 _imax_(IUINT32 a, IUINT32 b) {
|
|
128
|
+
return a >= b ? a : b;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static inline IUINT32 _ibound_(IUINT32 lower, IUINT32 middle, IUINT32 upper)
|
|
132
|
+
{
|
|
133
|
+
return _imin_(_imax_(lower, middle), upper);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static inline long _itimediff(IUINT32 later, IUINT32 earlier)
|
|
137
|
+
{
|
|
138
|
+
return ((IINT32)(later - earlier));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//---------------------------------------------------------------------
|
|
142
|
+
// manage segment
|
|
143
|
+
//---------------------------------------------------------------------
|
|
144
|
+
typedef struct IKCPSEG IKCPSEG;
|
|
145
|
+
|
|
146
|
+
static void* (*ikcp_malloc_hook)(size_t) = NULL;
|
|
147
|
+
static void (*ikcp_free_hook)(void *) = NULL;
|
|
148
|
+
|
|
149
|
+
// internal malloc
|
|
150
|
+
static void* ikcp_malloc(size_t size) {
|
|
151
|
+
if (ikcp_malloc_hook)
|
|
152
|
+
return ikcp_malloc_hook(size);
|
|
153
|
+
return malloc(size);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// internal free
|
|
157
|
+
static void ikcp_free(void *ptr) {
|
|
158
|
+
if (ikcp_free_hook) {
|
|
159
|
+
ikcp_free_hook(ptr);
|
|
160
|
+
} else {
|
|
161
|
+
free(ptr);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// redefine allocator
|
|
166
|
+
void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*))
|
|
167
|
+
{
|
|
168
|
+
ikcp_malloc_hook = new_malloc;
|
|
169
|
+
ikcp_free_hook = new_free;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// allocate a new kcp segment
|
|
173
|
+
static IKCPSEG* ikcp_segment_new(ikcpcb *kcp, int size)
|
|
174
|
+
{
|
|
175
|
+
return (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// delete a segment
|
|
179
|
+
static void ikcp_segment_delete(ikcpcb *kcp, IKCPSEG *seg)
|
|
180
|
+
{
|
|
181
|
+
ikcp_free(seg);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// write log
|
|
185
|
+
void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...)
|
|
186
|
+
{
|
|
187
|
+
char buffer[1024];
|
|
188
|
+
va_list argptr;
|
|
189
|
+
if ((mask & kcp->logmask) == 0 || kcp->writelog == 0) return;
|
|
190
|
+
va_start(argptr, fmt);
|
|
191
|
+
vsprintf(buffer, fmt, argptr);
|
|
192
|
+
va_end(argptr);
|
|
193
|
+
kcp->writelog(buffer, kcp, kcp->user);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// check log mask
|
|
197
|
+
static int ikcp_canlog(const ikcpcb *kcp, int mask)
|
|
198
|
+
{
|
|
199
|
+
if ((mask & kcp->logmask) == 0 || kcp->writelog == NULL) return 0;
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// output segment
|
|
204
|
+
static int ikcp_output(ikcpcb *kcp, const void *data, int size)
|
|
205
|
+
{
|
|
206
|
+
assert(kcp);
|
|
207
|
+
assert(kcp->output);
|
|
208
|
+
if (ikcp_canlog(kcp, IKCP_LOG_OUTPUT)) {
|
|
209
|
+
ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", (long)size);
|
|
210
|
+
}
|
|
211
|
+
if (size == 0) return 0;
|
|
212
|
+
return kcp->output((const char*)data, size, kcp, kcp->user);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// output queue
|
|
216
|
+
void ikcp_qprint(const char *name, const struct IQUEUEHEAD *head)
|
|
217
|
+
{
|
|
218
|
+
#if 0
|
|
219
|
+
const struct IQUEUEHEAD *p;
|
|
220
|
+
printf("<%s>: [", name);
|
|
221
|
+
for (p = head->next; p != head; p = p->next) {
|
|
222
|
+
const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node);
|
|
223
|
+
printf("(%lu %d)", (unsigned long)seg->sn, (int)(seg->ts % 10000));
|
|
224
|
+
if (p->next != head) printf(",");
|
|
225
|
+
}
|
|
226
|
+
printf("]\n");
|
|
227
|
+
#endif
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
//---------------------------------------------------------------------
|
|
232
|
+
// create a new kcpcb
|
|
233
|
+
//---------------------------------------------------------------------
|
|
234
|
+
ikcpcb* ikcp_create(IUINT32 conv, void *user)
|
|
235
|
+
{
|
|
236
|
+
ikcpcb *kcp = (ikcpcb*)ikcp_malloc(sizeof(struct IKCPCB));
|
|
237
|
+
if (kcp == NULL) return NULL;
|
|
238
|
+
kcp->conv = conv;
|
|
239
|
+
kcp->user = user;
|
|
240
|
+
kcp->snd_una = 0;
|
|
241
|
+
kcp->snd_nxt = 0;
|
|
242
|
+
kcp->rcv_nxt = 0;
|
|
243
|
+
kcp->ts_recent = 0;
|
|
244
|
+
kcp->ts_lastack = 0;
|
|
245
|
+
kcp->ts_probe = 0;
|
|
246
|
+
kcp->probe_wait = 0;
|
|
247
|
+
kcp->snd_wnd = IKCP_WND_SND;
|
|
248
|
+
kcp->rcv_wnd = IKCP_WND_RCV;
|
|
249
|
+
kcp->rmt_wnd = IKCP_WND_RCV;
|
|
250
|
+
kcp->cwnd = 0;
|
|
251
|
+
kcp->incr = 0;
|
|
252
|
+
kcp->probe = 0;
|
|
253
|
+
kcp->mtu = IKCP_MTU_DEF;
|
|
254
|
+
kcp->mss = kcp->mtu - IKCP_OVERHEAD;
|
|
255
|
+
kcp->stream = 0;
|
|
256
|
+
|
|
257
|
+
kcp->buffer = (char*)ikcp_malloc((kcp->mtu + IKCP_OVERHEAD) * 3);
|
|
258
|
+
if (kcp->buffer == NULL) {
|
|
259
|
+
ikcp_free(kcp);
|
|
260
|
+
return NULL;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
iqueue_init(&kcp->snd_queue);
|
|
264
|
+
iqueue_init(&kcp->rcv_queue);
|
|
265
|
+
iqueue_init(&kcp->snd_buf);
|
|
266
|
+
iqueue_init(&kcp->rcv_buf);
|
|
267
|
+
kcp->nrcv_buf = 0;
|
|
268
|
+
kcp->nsnd_buf = 0;
|
|
269
|
+
kcp->nrcv_que = 0;
|
|
270
|
+
kcp->nsnd_que = 0;
|
|
271
|
+
kcp->state = 0;
|
|
272
|
+
kcp->acklist = NULL;
|
|
273
|
+
kcp->ackblock = 0;
|
|
274
|
+
kcp->ackcount = 0;
|
|
275
|
+
kcp->ackedlen = 0;
|
|
276
|
+
kcp->rx_srtt = 0;
|
|
277
|
+
kcp->rx_rttval = 0;
|
|
278
|
+
kcp->rx_rto = IKCP_RTO_DEF;
|
|
279
|
+
kcp->rx_minrto = IKCP_RTO_MIN;
|
|
280
|
+
kcp->current = 0;
|
|
281
|
+
kcp->interval = IKCP_INTERVAL;
|
|
282
|
+
kcp->ts_flush = IKCP_INTERVAL;
|
|
283
|
+
kcp->nodelay = 0;
|
|
284
|
+
kcp->updated = 0;
|
|
285
|
+
kcp->logmask = 0;
|
|
286
|
+
kcp->ssthresh = IKCP_THRESH_INIT;
|
|
287
|
+
kcp->fastresend = 0;
|
|
288
|
+
kcp->fastlimit = IKCP_FASTACK_LIMIT;
|
|
289
|
+
kcp->nocwnd = 0;
|
|
290
|
+
kcp->xmit = 0;
|
|
291
|
+
kcp->dead_link = IKCP_DEADLINK;
|
|
292
|
+
kcp->output = NULL;
|
|
293
|
+
kcp->ccops = NULL;
|
|
294
|
+
kcp->congest = NULL;
|
|
295
|
+
kcp->writelog = NULL;
|
|
296
|
+
|
|
297
|
+
return kcp;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
//---------------------------------------------------------------------
|
|
302
|
+
// release a kcpcb
|
|
303
|
+
//---------------------------------------------------------------------
|
|
304
|
+
void ikcp_release(ikcpcb *kcp)
|
|
305
|
+
{
|
|
306
|
+
IKCPSEG *seg;
|
|
307
|
+
assert(kcp);
|
|
308
|
+
if (kcp) {
|
|
309
|
+
if (kcp->ccops && kcp->ccops->release) {
|
|
310
|
+
kcp->ccops->release(kcp);
|
|
311
|
+
}
|
|
312
|
+
while (!iqueue_is_empty(&kcp->snd_buf)) {
|
|
313
|
+
seg = iqueue_entry(kcp->snd_buf.next, IKCPSEG, node);
|
|
314
|
+
iqueue_del(&seg->node);
|
|
315
|
+
ikcp_segment_delete(kcp, seg);
|
|
316
|
+
}
|
|
317
|
+
while (!iqueue_is_empty(&kcp->rcv_buf)) {
|
|
318
|
+
seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node);
|
|
319
|
+
iqueue_del(&seg->node);
|
|
320
|
+
ikcp_segment_delete(kcp, seg);
|
|
321
|
+
}
|
|
322
|
+
while (!iqueue_is_empty(&kcp->snd_queue)) {
|
|
323
|
+
seg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node);
|
|
324
|
+
iqueue_del(&seg->node);
|
|
325
|
+
ikcp_segment_delete(kcp, seg);
|
|
326
|
+
}
|
|
327
|
+
while (!iqueue_is_empty(&kcp->rcv_queue)) {
|
|
328
|
+
seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node);
|
|
329
|
+
iqueue_del(&seg->node);
|
|
330
|
+
ikcp_segment_delete(kcp, seg);
|
|
331
|
+
}
|
|
332
|
+
if (kcp->buffer) {
|
|
333
|
+
ikcp_free(kcp->buffer);
|
|
334
|
+
}
|
|
335
|
+
if (kcp->acklist) {
|
|
336
|
+
ikcp_free(kcp->acklist);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
kcp->nrcv_buf = 0;
|
|
340
|
+
kcp->nsnd_buf = 0;
|
|
341
|
+
kcp->nrcv_que = 0;
|
|
342
|
+
kcp->nsnd_que = 0;
|
|
343
|
+
kcp->ackcount = 0;
|
|
344
|
+
kcp->buffer = NULL;
|
|
345
|
+
kcp->acklist = NULL;
|
|
346
|
+
ikcp_free(kcp);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
//---------------------------------------------------------------------
|
|
352
|
+
// set output callback, which will be invoked by kcp
|
|
353
|
+
//---------------------------------------------------------------------
|
|
354
|
+
void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len,
|
|
355
|
+
ikcpcb *kcp, void *user))
|
|
356
|
+
{
|
|
357
|
+
kcp->output = output;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
//---------------------------------------------------------------------
|
|
362
|
+
// upper-level recv: returns size, or a negative value for EAGAIN
|
|
363
|
+
//---------------------------------------------------------------------
|
|
364
|
+
int ikcp_recv(ikcpcb *kcp, char *buffer, int len)
|
|
365
|
+
{
|
|
366
|
+
struct IQUEUEHEAD *p;
|
|
367
|
+
int ispeek = (len < 0)? 1 : 0;
|
|
368
|
+
int peeksize;
|
|
369
|
+
int recover = 0;
|
|
370
|
+
IKCPSEG *seg;
|
|
371
|
+
assert(kcp);
|
|
372
|
+
|
|
373
|
+
if (iqueue_is_empty(&kcp->rcv_queue))
|
|
374
|
+
return -1;
|
|
375
|
+
|
|
376
|
+
if (len < 0) len = -len;
|
|
377
|
+
|
|
378
|
+
peeksize = ikcp_peeksize(kcp);
|
|
379
|
+
|
|
380
|
+
if (peeksize < 0)
|
|
381
|
+
return -2;
|
|
382
|
+
|
|
383
|
+
if (peeksize > len)
|
|
384
|
+
return -3;
|
|
385
|
+
|
|
386
|
+
if (kcp->nrcv_que >= kcp->rcv_wnd)
|
|
387
|
+
recover = 1;
|
|
388
|
+
|
|
389
|
+
// merge fragment
|
|
390
|
+
for (len = 0, p = kcp->rcv_queue.next; p != &kcp->rcv_queue; ) {
|
|
391
|
+
int fragment;
|
|
392
|
+
seg = iqueue_entry(p, IKCPSEG, node);
|
|
393
|
+
p = p->next;
|
|
394
|
+
|
|
395
|
+
if (buffer) {
|
|
396
|
+
memcpy(buffer, seg->data, seg->len);
|
|
397
|
+
buffer += seg->len;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
len += seg->len;
|
|
401
|
+
fragment = seg->frg;
|
|
402
|
+
|
|
403
|
+
if (ikcp_canlog(kcp, IKCP_LOG_RECV)) {
|
|
404
|
+
ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=%lu", (unsigned long)seg->sn);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (ispeek == 0) {
|
|
408
|
+
iqueue_del(&seg->node);
|
|
409
|
+
ikcp_segment_delete(kcp, seg);
|
|
410
|
+
kcp->nrcv_que--;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (fragment == 0)
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
assert(len == peeksize);
|
|
418
|
+
|
|
419
|
+
// move available data from rcv_buf -> rcv_queue
|
|
420
|
+
while (! iqueue_is_empty(&kcp->rcv_buf)) {
|
|
421
|
+
seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node);
|
|
422
|
+
if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) {
|
|
423
|
+
iqueue_del(&seg->node);
|
|
424
|
+
kcp->nrcv_buf--;
|
|
425
|
+
iqueue_add_tail(&seg->node, &kcp->rcv_queue);
|
|
426
|
+
kcp->nrcv_que++;
|
|
427
|
+
kcp->rcv_nxt++;
|
|
428
|
+
} else {
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// fast recover
|
|
434
|
+
if (kcp->nrcv_que < kcp->rcv_wnd && recover) {
|
|
435
|
+
// ready to send back IKCP_CMD_WINS in ikcp_flush
|
|
436
|
+
// tell remote my window size
|
|
437
|
+
kcp->probe |= IKCP_ASK_TELL;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return len;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
//---------------------------------------------------------------------
|
|
445
|
+
// peek data size
|
|
446
|
+
//---------------------------------------------------------------------
|
|
447
|
+
int ikcp_peeksize(const ikcpcb *kcp)
|
|
448
|
+
{
|
|
449
|
+
struct IQUEUEHEAD *p;
|
|
450
|
+
IKCPSEG *seg;
|
|
451
|
+
int length = 0;
|
|
452
|
+
|
|
453
|
+
assert(kcp);
|
|
454
|
+
|
|
455
|
+
if (iqueue_is_empty(&kcp->rcv_queue)) return -1;
|
|
456
|
+
|
|
457
|
+
seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node);
|
|
458
|
+
if (seg->frg == 0) return seg->len;
|
|
459
|
+
|
|
460
|
+
if (kcp->nrcv_que < seg->frg + 1) return -1;
|
|
461
|
+
|
|
462
|
+
for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) {
|
|
463
|
+
seg = iqueue_entry(p, IKCPSEG, node);
|
|
464
|
+
length += seg->len;
|
|
465
|
+
if (seg->frg == 0) break;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return length;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
//---------------------------------------------------------------------
|
|
473
|
+
// upper-level send: returns size, or a negative value on error
|
|
474
|
+
//---------------------------------------------------------------------
|
|
475
|
+
int ikcp_send(ikcpcb *kcp, const char *buffer, int len)
|
|
476
|
+
{
|
|
477
|
+
IKCPSEG *seg;
|
|
478
|
+
int count, i;
|
|
479
|
+
int sent = 0;
|
|
480
|
+
|
|
481
|
+
assert(kcp->mss > 0);
|
|
482
|
+
if (len < 0) return -1;
|
|
483
|
+
|
|
484
|
+
// append to previous segment in streaming mode (if possible)
|
|
485
|
+
if (kcp->stream != 0) {
|
|
486
|
+
if (!iqueue_is_empty(&kcp->snd_queue)) {
|
|
487
|
+
IKCPSEG *old = iqueue_entry(kcp->snd_queue.prev, IKCPSEG, node);
|
|
488
|
+
if (old->len < kcp->mss) {
|
|
489
|
+
int capacity = kcp->mss - old->len;
|
|
490
|
+
int extend = (len < capacity)? len : capacity;
|
|
491
|
+
seg = ikcp_segment_new(kcp, old->len + extend);
|
|
492
|
+
assert(seg);
|
|
493
|
+
if (seg == NULL) {
|
|
494
|
+
return -2;
|
|
495
|
+
}
|
|
496
|
+
iqueue_add_tail(&seg->node, &kcp->snd_queue);
|
|
497
|
+
memcpy(seg->data, old->data, old->len);
|
|
498
|
+
if (buffer) {
|
|
499
|
+
memcpy(seg->data + old->len, buffer, extend);
|
|
500
|
+
buffer += extend;
|
|
501
|
+
}
|
|
502
|
+
seg->len = old->len + extend;
|
|
503
|
+
seg->frg = 0;
|
|
504
|
+
len -= extend;
|
|
505
|
+
iqueue_del_init(&old->node);
|
|
506
|
+
ikcp_segment_delete(kcp, old);
|
|
507
|
+
sent = extend;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (len <= 0) {
|
|
511
|
+
return sent;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (len <= (int)kcp->mss) count = 1;
|
|
516
|
+
else count = (len + kcp->mss - 1) / kcp->mss;
|
|
517
|
+
|
|
518
|
+
if (count >= (int)IKCP_WND_RCV) {
|
|
519
|
+
if (kcp->stream != 0 && sent > 0)
|
|
520
|
+
return sent;
|
|
521
|
+
return -2;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (count == 0) count = 1;
|
|
525
|
+
|
|
526
|
+
// fragment
|
|
527
|
+
for (i = 0; i < count; i++) {
|
|
528
|
+
int size = len > (int)kcp->mss ? (int)kcp->mss : len;
|
|
529
|
+
seg = ikcp_segment_new(kcp, size);
|
|
530
|
+
assert(seg);
|
|
531
|
+
if (seg == NULL) {
|
|
532
|
+
return -2;
|
|
533
|
+
}
|
|
534
|
+
if (buffer && len > 0) {
|
|
535
|
+
memcpy(seg->data, buffer, size);
|
|
536
|
+
}
|
|
537
|
+
seg->len = size;
|
|
538
|
+
seg->frg = (kcp->stream == 0)? (count - i - 1) : 0;
|
|
539
|
+
iqueue_init(&seg->node);
|
|
540
|
+
iqueue_add_tail(&seg->node, &kcp->snd_queue);
|
|
541
|
+
kcp->nsnd_que++;
|
|
542
|
+
if (buffer) {
|
|
543
|
+
buffer += size;
|
|
544
|
+
}
|
|
545
|
+
len -= size;
|
|
546
|
+
sent += size;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return sent;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
//---------------------------------------------------------------------
|
|
554
|
+
// parse ack
|
|
555
|
+
//---------------------------------------------------------------------
|
|
556
|
+
static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt)
|
|
557
|
+
{
|
|
558
|
+
IINT32 rto = 0;
|
|
559
|
+
if (kcp->rx_srtt == 0) {
|
|
560
|
+
kcp->rx_srtt = rtt;
|
|
561
|
+
kcp->rx_rttval = rtt / 2;
|
|
562
|
+
} else {
|
|
563
|
+
long delta = rtt - kcp->rx_srtt;
|
|
564
|
+
if (delta < 0) delta = -delta;
|
|
565
|
+
kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4;
|
|
566
|
+
kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8;
|
|
567
|
+
if (kcp->rx_srtt < 1) kcp->rx_srtt = 1;
|
|
568
|
+
}
|
|
569
|
+
rto = kcp->rx_srtt + _imax_(kcp->interval, 4 * kcp->rx_rttval);
|
|
570
|
+
kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX);
|
|
571
|
+
if (kcp->ccops && kcp->ccops->on_rtt) {
|
|
572
|
+
kcp->ccops->on_rtt(kcp, rtt);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
static void ikcp_shrink_buf(ikcpcb *kcp)
|
|
577
|
+
{
|
|
578
|
+
struct IQUEUEHEAD *p = kcp->snd_buf.next;
|
|
579
|
+
if (p != &kcp->snd_buf) {
|
|
580
|
+
IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node);
|
|
581
|
+
kcp->snd_una = seg->sn;
|
|
582
|
+
} else {
|
|
583
|
+
kcp->snd_una = kcp->snd_nxt;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
static void ikcp_parse_ack(ikcpcb *kcp, IUINT32 sn)
|
|
588
|
+
{
|
|
589
|
+
struct IQUEUEHEAD *p, *next;
|
|
590
|
+
IINT32 pkt_rtt;
|
|
591
|
+
|
|
592
|
+
if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0)
|
|
593
|
+
return;
|
|
594
|
+
|
|
595
|
+
for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) {
|
|
596
|
+
IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node);
|
|
597
|
+
next = p->next;
|
|
598
|
+
if (sn == seg->sn) {
|
|
599
|
+
kcp->ackedlen += seg->len;
|
|
600
|
+
if (kcp->ccops && kcp->ccops->on_pkt_acked) {
|
|
601
|
+
pkt_rtt = -1;
|
|
602
|
+
if (_itimediff(kcp->current, seg->ts) >= 0) {
|
|
603
|
+
pkt_rtt = _itimediff(kcp->current, seg->ts);
|
|
604
|
+
}
|
|
605
|
+
kcp->ccops->on_pkt_acked(kcp, seg->sn, seg->ts,
|
|
606
|
+
seg->len, pkt_rtt, seg->xmit);
|
|
607
|
+
}
|
|
608
|
+
iqueue_del(p);
|
|
609
|
+
ikcp_segment_delete(kcp, seg);
|
|
610
|
+
kcp->nsnd_buf--;
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
if (_itimediff(sn, seg->sn) < 0) {
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una)
|
|
620
|
+
{
|
|
621
|
+
struct IQUEUEHEAD *p, *next;
|
|
622
|
+
for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) {
|
|
623
|
+
IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node);
|
|
624
|
+
next = p->next;
|
|
625
|
+
if (_itimediff(una, seg->sn) > 0) {
|
|
626
|
+
kcp->ackedlen += seg->len;
|
|
627
|
+
if (kcp->ccops && kcp->ccops->on_pkt_acked) {
|
|
628
|
+
kcp->ccops->on_pkt_acked(kcp, seg->sn, seg->ts,
|
|
629
|
+
seg->len, -1, seg->xmit);
|
|
630
|
+
}
|
|
631
|
+
iqueue_del(p);
|
|
632
|
+
ikcp_segment_delete(kcp, seg);
|
|
633
|
+
kcp->nsnd_buf--;
|
|
634
|
+
} else {
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn, IUINT32 ts)
|
|
641
|
+
{
|
|
642
|
+
struct IQUEUEHEAD *p, *next;
|
|
643
|
+
|
|
644
|
+
if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0)
|
|
645
|
+
return;
|
|
646
|
+
|
|
647
|
+
for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) {
|
|
648
|
+
IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node);
|
|
649
|
+
next = p->next;
|
|
650
|
+
if (_itimediff(sn, seg->sn) < 0) {
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
else if (sn != seg->sn) {
|
|
654
|
+
#ifndef IKCP_FASTACK_CONSERVE
|
|
655
|
+
seg->fastack++;
|
|
656
|
+
#else
|
|
657
|
+
if (_itimediff(ts, seg->ts) >= 0)
|
|
658
|
+
seg->fastack++;
|
|
659
|
+
#endif
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
//---------------------------------------------------------------------
|
|
666
|
+
// ack append
|
|
667
|
+
//---------------------------------------------------------------------
|
|
668
|
+
static void ikcp_ack_push(ikcpcb *kcp, IUINT32 sn, IUINT32 ts)
|
|
669
|
+
{
|
|
670
|
+
IUINT32 newsize = kcp->ackcount + 1;
|
|
671
|
+
IUINT32 *ptr;
|
|
672
|
+
|
|
673
|
+
if (newsize > kcp->ackblock) {
|
|
674
|
+
IUINT32 *acklist;
|
|
675
|
+
IUINT32 newblock;
|
|
676
|
+
|
|
677
|
+
for (newblock = 8; newblock < newsize; newblock <<= 1);
|
|
678
|
+
acklist = (IUINT32*)ikcp_malloc(newblock * sizeof(IUINT32) * 2);
|
|
679
|
+
|
|
680
|
+
if (acklist == NULL) {
|
|
681
|
+
assert(acklist != NULL);
|
|
682
|
+
abort();
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if (kcp->acklist != NULL) {
|
|
686
|
+
IUINT32 x;
|
|
687
|
+
for (x = 0; x < kcp->ackcount; x++) {
|
|
688
|
+
acklist[x * 2 + 0] = kcp->acklist[x * 2 + 0];
|
|
689
|
+
acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1];
|
|
690
|
+
}
|
|
691
|
+
ikcp_free(kcp->acklist);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
kcp->acklist = acklist;
|
|
695
|
+
kcp->ackblock = newblock;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
ptr = &kcp->acklist[kcp->ackcount * 2];
|
|
699
|
+
ptr[0] = sn;
|
|
700
|
+
ptr[1] = ts;
|
|
701
|
+
kcp->ackcount++;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
static void ikcp_ack_get(const ikcpcb *kcp, int p, IUINT32 *sn, IUINT32 *ts)
|
|
705
|
+
{
|
|
706
|
+
if (sn) sn[0] = kcp->acklist[p * 2 + 0];
|
|
707
|
+
if (ts) ts[0] = kcp->acklist[p * 2 + 1];
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
//---------------------------------------------------------------------
|
|
712
|
+
// parse data
|
|
713
|
+
//---------------------------------------------------------------------
|
|
714
|
+
void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg)
|
|
715
|
+
{
|
|
716
|
+
struct IQUEUEHEAD *p, *prev;
|
|
717
|
+
IUINT32 sn = newseg->sn;
|
|
718
|
+
int repeat = 0;
|
|
719
|
+
|
|
720
|
+
if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 ||
|
|
721
|
+
_itimediff(sn, kcp->rcv_nxt) < 0) {
|
|
722
|
+
ikcp_segment_delete(kcp, newseg);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) {
|
|
727
|
+
IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node);
|
|
728
|
+
prev = p->prev;
|
|
729
|
+
if (seg->sn == sn) {
|
|
730
|
+
repeat = 1;
|
|
731
|
+
break;
|
|
732
|
+
}
|
|
733
|
+
if (_itimediff(sn, seg->sn) > 0) {
|
|
734
|
+
break;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (repeat == 0) {
|
|
739
|
+
iqueue_init(&newseg->node);
|
|
740
|
+
iqueue_add(&newseg->node, p);
|
|
741
|
+
kcp->nrcv_buf++;
|
|
742
|
+
} else {
|
|
743
|
+
ikcp_segment_delete(kcp, newseg);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
#if 0
|
|
747
|
+
ikcp_qprint("rcvbuf", &kcp->rcv_buf);
|
|
748
|
+
printf("rcv_nxt=%lu\n", kcp->rcv_nxt);
|
|
749
|
+
#endif
|
|
750
|
+
|
|
751
|
+
// move available data from rcv_buf -> rcv_queue
|
|
752
|
+
while (! iqueue_is_empty(&kcp->rcv_buf)) {
|
|
753
|
+
IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node);
|
|
754
|
+
if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) {
|
|
755
|
+
iqueue_del(&seg->node);
|
|
756
|
+
kcp->nrcv_buf--;
|
|
757
|
+
iqueue_add_tail(&seg->node, &kcp->rcv_queue);
|
|
758
|
+
kcp->nrcv_que++;
|
|
759
|
+
kcp->rcv_nxt++;
|
|
760
|
+
} else {
|
|
761
|
+
break;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
#if 0
|
|
766
|
+
ikcp_qprint("queue", &kcp->rcv_queue);
|
|
767
|
+
printf("rcv_nxt=%lu\n", kcp->rcv_nxt);
|
|
768
|
+
#endif
|
|
769
|
+
|
|
770
|
+
#if 1
|
|
771
|
+
// printf("snd(buf=%d, queue=%d)\n", kcp->nsnd_buf, kcp->nsnd_que);
|
|
772
|
+
// printf("rcv(buf=%d, queue=%d)\n", kcp->nrcv_buf, kcp->nrcv_que);
|
|
773
|
+
#endif
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
//---------------------------------------------------------------------
|
|
778
|
+
// input data
|
|
779
|
+
//---------------------------------------------------------------------
|
|
780
|
+
int ikcp_input(ikcpcb *kcp, const char *data, long size)
|
|
781
|
+
{
|
|
782
|
+
IUINT32 prev_una = kcp->snd_una;
|
|
783
|
+
IUINT32 prev_nsnd_buf = kcp->nsnd_buf;
|
|
784
|
+
IUINT32 acked_segs, prior_in_flight;
|
|
785
|
+
IUINT32 maxack = 0, latest_ts = 0;
|
|
786
|
+
int flag = 0;
|
|
787
|
+
|
|
788
|
+
kcp->ackedlen = 0;
|
|
789
|
+
|
|
790
|
+
if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) {
|
|
791
|
+
ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", (int)size);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (data == NULL || (int)size < (int)IKCP_OVERHEAD) return -1;
|
|
795
|
+
|
|
796
|
+
while (1) {
|
|
797
|
+
IUINT32 ts, sn, len, una, conv;
|
|
798
|
+
IUINT16 wnd;
|
|
799
|
+
IUINT8 cmd, frg;
|
|
800
|
+
IKCPSEG *seg;
|
|
801
|
+
|
|
802
|
+
if (size < (int)IKCP_OVERHEAD) break;
|
|
803
|
+
|
|
804
|
+
data = ikcp_decode32u(data, &conv);
|
|
805
|
+
if (conv != kcp->conv) return -1;
|
|
806
|
+
|
|
807
|
+
data = ikcp_decode8u(data, &cmd);
|
|
808
|
+
data = ikcp_decode8u(data, &frg);
|
|
809
|
+
data = ikcp_decode16u(data, &wnd);
|
|
810
|
+
data = ikcp_decode32u(data, &ts);
|
|
811
|
+
data = ikcp_decode32u(data, &sn);
|
|
812
|
+
data = ikcp_decode32u(data, &una);
|
|
813
|
+
data = ikcp_decode32u(data, &len);
|
|
814
|
+
|
|
815
|
+
size -= IKCP_OVERHEAD;
|
|
816
|
+
|
|
817
|
+
if ((long)size < (long)len || (int)len < 0) return -2;
|
|
818
|
+
|
|
819
|
+
if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK &&
|
|
820
|
+
cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS)
|
|
821
|
+
return -3;
|
|
822
|
+
|
|
823
|
+
kcp->rmt_wnd = wnd;
|
|
824
|
+
ikcp_parse_una(kcp, una);
|
|
825
|
+
ikcp_shrink_buf(kcp);
|
|
826
|
+
|
|
827
|
+
if (cmd == IKCP_CMD_ACK) {
|
|
828
|
+
if (_itimediff(kcp->current, ts) >= 0) {
|
|
829
|
+
ikcp_update_ack(kcp, _itimediff(kcp->current, ts));
|
|
830
|
+
}
|
|
831
|
+
ikcp_parse_ack(kcp, sn);
|
|
832
|
+
ikcp_shrink_buf(kcp);
|
|
833
|
+
if (flag == 0) {
|
|
834
|
+
flag = 1;
|
|
835
|
+
maxack = sn;
|
|
836
|
+
latest_ts = ts;
|
|
837
|
+
} else {
|
|
838
|
+
if (_itimediff(sn, maxack) > 0) {
|
|
839
|
+
#ifndef IKCP_FASTACK_CONSERVE
|
|
840
|
+
maxack = sn;
|
|
841
|
+
latest_ts = ts;
|
|
842
|
+
#else
|
|
843
|
+
if (_itimediff(ts, latest_ts) > 0) {
|
|
844
|
+
maxack = sn;
|
|
845
|
+
latest_ts = ts;
|
|
846
|
+
}
|
|
847
|
+
#endif
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) {
|
|
851
|
+
ikcp_log(kcp, IKCP_LOG_IN_ACK,
|
|
852
|
+
"input ack: sn=%lu rtt=%ld rto=%ld", (unsigned long)sn,
|
|
853
|
+
(long)_itimediff(kcp->current, ts),
|
|
854
|
+
(long)kcp->rx_rto);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
else if (cmd == IKCP_CMD_PUSH) {
|
|
858
|
+
if (ikcp_canlog(kcp, IKCP_LOG_IN_DATA)) {
|
|
859
|
+
ikcp_log(kcp, IKCP_LOG_IN_DATA,
|
|
860
|
+
"input psh: sn=%lu ts=%lu", (unsigned long)sn, (unsigned long)ts);
|
|
861
|
+
}
|
|
862
|
+
if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) {
|
|
863
|
+
ikcp_ack_push(kcp, sn, ts);
|
|
864
|
+
if (_itimediff(sn, kcp->rcv_nxt) >= 0) {
|
|
865
|
+
seg = ikcp_segment_new(kcp, len);
|
|
866
|
+
seg->conv = conv;
|
|
867
|
+
seg->cmd = cmd;
|
|
868
|
+
seg->frg = frg;
|
|
869
|
+
seg->wnd = wnd;
|
|
870
|
+
seg->ts = ts;
|
|
871
|
+
seg->sn = sn;
|
|
872
|
+
seg->una = una;
|
|
873
|
+
seg->len = len;
|
|
874
|
+
|
|
875
|
+
if (len > 0) {
|
|
876
|
+
memcpy(seg->data, data, len);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
ikcp_parse_data(kcp, seg);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
else if (cmd == IKCP_CMD_WASK) {
|
|
884
|
+
// ready to send back IKCP_CMD_WINS in ikcp_flush
|
|
885
|
+
// tell remote my window size
|
|
886
|
+
kcp->probe |= IKCP_ASK_TELL;
|
|
887
|
+
if (ikcp_canlog(kcp, IKCP_LOG_IN_PROBE)) {
|
|
888
|
+
ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe");
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
else if (cmd == IKCP_CMD_WINS) {
|
|
892
|
+
// do nothing
|
|
893
|
+
if (ikcp_canlog(kcp, IKCP_LOG_IN_WINS)) {
|
|
894
|
+
ikcp_log(kcp, IKCP_LOG_IN_WINS,
|
|
895
|
+
"input wins: %lu", (unsigned long)(wnd));
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
return -3;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
data += len;
|
|
903
|
+
size -= len;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (flag != 0) {
|
|
907
|
+
ikcp_parse_fastack(kcp, maxack, latest_ts);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
if (_itimediff(kcp->snd_una, prev_una) > 0) {
|
|
911
|
+
acked_segs = kcp->snd_una - prev_una;
|
|
912
|
+
prior_in_flight = prev_nsnd_buf;
|
|
913
|
+
if (kcp->ccops && kcp->ccops->on_ack) {
|
|
914
|
+
kcp->ccops->on_ack(kcp, acked_segs, kcp->ackedlen,
|
|
915
|
+
prior_in_flight);
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
if (kcp->cwnd < kcp->rmt_wnd) {
|
|
919
|
+
IUINT32 mss = kcp->mss;
|
|
920
|
+
if (kcp->cwnd < kcp->ssthresh) {
|
|
921
|
+
kcp->cwnd++;
|
|
922
|
+
kcp->incr += mss;
|
|
923
|
+
} else {
|
|
924
|
+
if (kcp->incr < mss) kcp->incr = mss;
|
|
925
|
+
kcp->incr += (mss * mss) / kcp->incr + (mss / 16);
|
|
926
|
+
if ((kcp->cwnd + 1) * mss <= kcp->incr) {
|
|
927
|
+
#if 1
|
|
928
|
+
kcp->cwnd = (kcp->incr + mss - 1) / ((mss > 0)? mss : 1);
|
|
929
|
+
#else
|
|
930
|
+
kcp->cwnd++;
|
|
931
|
+
#endif
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
if (kcp->cwnd > kcp->rmt_wnd) {
|
|
935
|
+
kcp->cwnd = kcp->rmt_wnd;
|
|
936
|
+
kcp->incr = kcp->rmt_wnd * mss;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
return 0;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
//---------------------------------------------------------------------
|
|
947
|
+
// ikcp_encode_seg
|
|
948
|
+
//---------------------------------------------------------------------
|
|
949
|
+
static char *ikcp_encode_seg(char *ptr, const IKCPSEG *seg)
|
|
950
|
+
{
|
|
951
|
+
ptr = ikcp_encode32u(ptr, seg->conv);
|
|
952
|
+
ptr = ikcp_encode8u(ptr, (IUINT8)seg->cmd);
|
|
953
|
+
ptr = ikcp_encode8u(ptr, (IUINT8)seg->frg);
|
|
954
|
+
ptr = ikcp_encode16u(ptr, (IUINT16)seg->wnd);
|
|
955
|
+
ptr = ikcp_encode32u(ptr, seg->ts);
|
|
956
|
+
ptr = ikcp_encode32u(ptr, seg->sn);
|
|
957
|
+
ptr = ikcp_encode32u(ptr, seg->una);
|
|
958
|
+
ptr = ikcp_encode32u(ptr, seg->len);
|
|
959
|
+
return ptr;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
static int ikcp_wnd_unused(const ikcpcb *kcp)
|
|
963
|
+
{
|
|
964
|
+
if (kcp->nrcv_que < kcp->rcv_wnd) {
|
|
965
|
+
return kcp->rcv_wnd - kcp->nrcv_que;
|
|
966
|
+
}
|
|
967
|
+
return 0;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
//---------------------------------------------------------------------
|
|
972
|
+
// ikcp_flush
|
|
973
|
+
//---------------------------------------------------------------------
|
|
974
|
+
void ikcp_flush(ikcpcb *kcp)
|
|
975
|
+
{
|
|
976
|
+
IUINT32 current = kcp->current;
|
|
977
|
+
char *buffer = kcp->buffer;
|
|
978
|
+
char *ptr = buffer;
|
|
979
|
+
int count, size, i;
|
|
980
|
+
IUINT32 resent, cwnd;
|
|
981
|
+
IUINT32 rtomin;
|
|
982
|
+
IUINT32 prior_cwnd;
|
|
983
|
+
IUINT32 eff_cwnd, cur_inflight;
|
|
984
|
+
IINT32 pacing_budget = -1;
|
|
985
|
+
struct IQUEUEHEAD *p;
|
|
986
|
+
int change = 0;
|
|
987
|
+
int lost = 0;
|
|
988
|
+
IKCPSEG seg;
|
|
989
|
+
|
|
990
|
+
// 'ikcp_update' hasn't been called yet.
|
|
991
|
+
if (kcp->updated == 0) return;
|
|
992
|
+
|
|
993
|
+
if (kcp->ccops && kcp->ccops->on_tick) {
|
|
994
|
+
kcp->ccops->on_tick(kcp);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
if (kcp->ccops && kcp->ccops->pacing_rate) {
|
|
998
|
+
pacing_budget = (IINT32)kcp->ccops->pacing_rate(kcp);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
prior_cwnd = kcp->cwnd;
|
|
1002
|
+
|
|
1003
|
+
seg.conv = kcp->conv;
|
|
1004
|
+
seg.cmd = IKCP_CMD_ACK;
|
|
1005
|
+
seg.frg = 0;
|
|
1006
|
+
seg.wnd = ikcp_wnd_unused(kcp);
|
|
1007
|
+
seg.una = kcp->rcv_nxt;
|
|
1008
|
+
seg.len = 0;
|
|
1009
|
+
seg.sn = 0;
|
|
1010
|
+
seg.ts = 0;
|
|
1011
|
+
|
|
1012
|
+
// flush acknowledges
|
|
1013
|
+
count = kcp->ackcount;
|
|
1014
|
+
for (i = 0; i < count; i++) {
|
|
1015
|
+
size = (int)(ptr - buffer);
|
|
1016
|
+
if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) {
|
|
1017
|
+
ikcp_output(kcp, buffer, size);
|
|
1018
|
+
ptr = buffer;
|
|
1019
|
+
}
|
|
1020
|
+
ikcp_ack_get(kcp, i, &seg.sn, &seg.ts);
|
|
1021
|
+
ptr = ikcp_encode_seg(ptr, &seg);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
kcp->ackcount = 0;
|
|
1025
|
+
|
|
1026
|
+
// probe window size (if remote window size equals zero)
|
|
1027
|
+
if (kcp->rmt_wnd == 0) {
|
|
1028
|
+
if (kcp->probe_wait == 0) {
|
|
1029
|
+
kcp->probe_wait = IKCP_PROBE_INIT;
|
|
1030
|
+
kcp->ts_probe = kcp->current + kcp->probe_wait;
|
|
1031
|
+
}
|
|
1032
|
+
else {
|
|
1033
|
+
if (_itimediff(kcp->current, kcp->ts_probe) >= 0) {
|
|
1034
|
+
if (kcp->probe_wait < IKCP_PROBE_INIT)
|
|
1035
|
+
kcp->probe_wait = IKCP_PROBE_INIT;
|
|
1036
|
+
kcp->probe_wait += kcp->probe_wait / 2;
|
|
1037
|
+
if (kcp->probe_wait > IKCP_PROBE_LIMIT)
|
|
1038
|
+
kcp->probe_wait = IKCP_PROBE_LIMIT;
|
|
1039
|
+
kcp->ts_probe = kcp->current + kcp->probe_wait;
|
|
1040
|
+
kcp->probe |= IKCP_ASK_SEND;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
} else {
|
|
1044
|
+
kcp->ts_probe = 0;
|
|
1045
|
+
kcp->probe_wait = 0;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// flush window probing commands
|
|
1049
|
+
if (kcp->probe & IKCP_ASK_SEND) {
|
|
1050
|
+
seg.cmd = IKCP_CMD_WASK;
|
|
1051
|
+
size = (int)(ptr - buffer);
|
|
1052
|
+
if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) {
|
|
1053
|
+
ikcp_output(kcp, buffer, size);
|
|
1054
|
+
ptr = buffer;
|
|
1055
|
+
}
|
|
1056
|
+
ptr = ikcp_encode_seg(ptr, &seg);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// flush window probing commands
|
|
1060
|
+
if (kcp->probe & IKCP_ASK_TELL) {
|
|
1061
|
+
seg.cmd = IKCP_CMD_WINS;
|
|
1062
|
+
size = (int)(ptr - buffer);
|
|
1063
|
+
if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) {
|
|
1064
|
+
ikcp_output(kcp, buffer, size);
|
|
1065
|
+
ptr = buffer;
|
|
1066
|
+
}
|
|
1067
|
+
ptr = ikcp_encode_seg(ptr, &seg);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
kcp->probe = 0;
|
|
1071
|
+
|
|
1072
|
+
// calculate window size
|
|
1073
|
+
cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd);
|
|
1074
|
+
if (kcp->ccops != NULL || kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd);
|
|
1075
|
+
|
|
1076
|
+
// move data from snd_queue to snd_buf
|
|
1077
|
+
while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) {
|
|
1078
|
+
IKCPSEG *newseg;
|
|
1079
|
+
if (iqueue_is_empty(&kcp->snd_queue)) break;
|
|
1080
|
+
|
|
1081
|
+
newseg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node);
|
|
1082
|
+
|
|
1083
|
+
iqueue_del(&newseg->node);
|
|
1084
|
+
iqueue_add_tail(&newseg->node, &kcp->snd_buf);
|
|
1085
|
+
kcp->nsnd_que--;
|
|
1086
|
+
kcp->nsnd_buf++;
|
|
1087
|
+
|
|
1088
|
+
newseg->conv = kcp->conv;
|
|
1089
|
+
newseg->cmd = IKCP_CMD_PUSH;
|
|
1090
|
+
newseg->wnd = seg.wnd;
|
|
1091
|
+
newseg->ts = current;
|
|
1092
|
+
newseg->sn = kcp->snd_nxt++;
|
|
1093
|
+
newseg->una = kcp->rcv_nxt;
|
|
1094
|
+
newseg->resendts = current;
|
|
1095
|
+
newseg->rto = kcp->rx_rto;
|
|
1096
|
+
newseg->fastack = 0;
|
|
1097
|
+
newseg->xmit = 0;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// check on_app_limited
|
|
1101
|
+
if (kcp->ccops && kcp->ccops->on_app_limited) {
|
|
1102
|
+
if (iqueue_is_empty(&kcp->snd_queue)) {
|
|
1103
|
+
eff_cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd);
|
|
1104
|
+
eff_cwnd = _imin_(kcp->cwnd, eff_cwnd);
|
|
1105
|
+
cur_inflight = kcp->nsnd_buf;
|
|
1106
|
+
if (cur_inflight < eff_cwnd) {
|
|
1107
|
+
kcp->ccops->on_app_limited(kcp, cur_inflight);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// calculate resent
|
|
1113
|
+
resent = (kcp->fastresend > 0)? (IUINT32)kcp->fastresend : 0xffffffff;
|
|
1114
|
+
rtomin = (kcp->nodelay == 0)? (kcp->rx_rto >> 3) : 0;
|
|
1115
|
+
|
|
1116
|
+
// flush data segments
|
|
1117
|
+
for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) {
|
|
1118
|
+
IKCPSEG *segment = iqueue_entry(p, IKCPSEG, node);
|
|
1119
|
+
int needsend = 0;
|
|
1120
|
+
if (segment->xmit == 0) {
|
|
1121
|
+
needsend = 1;
|
|
1122
|
+
segment->xmit++;
|
|
1123
|
+
segment->rto = kcp->rx_rto;
|
|
1124
|
+
segment->resendts = current + segment->rto + rtomin;
|
|
1125
|
+
}
|
|
1126
|
+
else if (_itimediff(current, segment->resendts) >= 0) {
|
|
1127
|
+
needsend = 1;
|
|
1128
|
+
segment->xmit++;
|
|
1129
|
+
kcp->xmit++;
|
|
1130
|
+
if (kcp->nodelay == 0) {
|
|
1131
|
+
segment->rto += _imax_(segment->rto, (IUINT32)kcp->rx_rto);
|
|
1132
|
+
} else {
|
|
1133
|
+
IINT32 step = (kcp->nodelay < 2)?
|
|
1134
|
+
((IINT32)(segment->rto)) : kcp->rx_rto;
|
|
1135
|
+
segment->rto += step / 2;
|
|
1136
|
+
}
|
|
1137
|
+
segment->resendts = current + segment->rto;
|
|
1138
|
+
lost = 1;
|
|
1139
|
+
}
|
|
1140
|
+
else if (segment->fastack >= resent) {
|
|
1141
|
+
if ((int)segment->xmit <= kcp->fastlimit ||
|
|
1142
|
+
kcp->fastlimit <= 0) {
|
|
1143
|
+
needsend = 1;
|
|
1144
|
+
segment->xmit++;
|
|
1145
|
+
segment->fastack = 0;
|
|
1146
|
+
segment->resendts = current + segment->rto;
|
|
1147
|
+
change++;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (needsend) {
|
|
1152
|
+
int need;
|
|
1153
|
+
segment->ts = current;
|
|
1154
|
+
segment->wnd = seg.wnd;
|
|
1155
|
+
segment->una = kcp->rcv_nxt;
|
|
1156
|
+
|
|
1157
|
+
if (pacing_budget >= 0 && pacing_budget < (IINT32)segment->len) {
|
|
1158
|
+
break;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
if (kcp->ccops && kcp->ccops->on_pkt_sent) {
|
|
1162
|
+
kcp->ccops->on_pkt_sent(kcp, segment->sn, current,
|
|
1163
|
+
segment->len, kcp->nsnd_buf, segment->xmit);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
size = (int)(ptr - buffer);
|
|
1167
|
+
need = IKCP_OVERHEAD + segment->len;
|
|
1168
|
+
|
|
1169
|
+
if (size + need > (int)kcp->mtu) {
|
|
1170
|
+
ikcp_output(kcp, buffer, size);
|
|
1171
|
+
ptr = buffer;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
ptr = ikcp_encode_seg(ptr, segment);
|
|
1175
|
+
|
|
1176
|
+
if (segment->len > 0) {
|
|
1177
|
+
memcpy(ptr, segment->data, segment->len);
|
|
1178
|
+
ptr += segment->len;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
if (pacing_budget >= 0) {
|
|
1182
|
+
pacing_budget -= (IINT32)segment->len;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (segment->xmit >= kcp->dead_link) {
|
|
1186
|
+
kcp->state = (IUINT32)-1;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// flash remaining segments
|
|
1192
|
+
size = (int)(ptr - buffer);
|
|
1193
|
+
if (size > 0) {
|
|
1194
|
+
ikcp_output(kcp, buffer, size);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// update ssthresh
|
|
1198
|
+
if (change) {
|
|
1199
|
+
if (kcp->ccops && kcp->ccops->on_fast_retransmit) {
|
|
1200
|
+
kcp->ccops->on_fast_retransmit(kcp, (IUINT32)change,
|
|
1201
|
+
kcp->nsnd_buf, prior_cwnd);
|
|
1202
|
+
}
|
|
1203
|
+
else {
|
|
1204
|
+
IUINT32 inflight = kcp->snd_nxt - kcp->snd_una;
|
|
1205
|
+
kcp->ssthresh = inflight / 2;
|
|
1206
|
+
if (kcp->ssthresh < IKCP_THRESH_MIN)
|
|
1207
|
+
kcp->ssthresh = IKCP_THRESH_MIN;
|
|
1208
|
+
kcp->cwnd = kcp->ssthresh + resent;
|
|
1209
|
+
kcp->incr = kcp->cwnd * kcp->mss;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
if (lost) {
|
|
1214
|
+
if (kcp->ccops && kcp->ccops->on_timeout) {
|
|
1215
|
+
kcp->ccops->on_timeout(kcp, prior_cwnd);
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
kcp->ssthresh = prior_cwnd / 2;
|
|
1219
|
+
if (kcp->ssthresh < IKCP_THRESH_MIN)
|
|
1220
|
+
kcp->ssthresh = IKCP_THRESH_MIN;
|
|
1221
|
+
kcp->cwnd = 1;
|
|
1222
|
+
kcp->incr = kcp->mss;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
if (kcp->cwnd < 1) {
|
|
1227
|
+
kcp->cwnd = 1;
|
|
1228
|
+
kcp->incr = kcp->mss;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
//---------------------------------------------------------------------
|
|
1234
|
+
// update state (call it repeatedly, every 10ms-100ms), or you can ask
|
|
1235
|
+
// ikcp_check when to call it again (if no ikcp_input/_send calls occur).
|
|
1236
|
+
// 'current' - current timestamp in milliseconds.
|
|
1237
|
+
//---------------------------------------------------------------------
|
|
1238
|
+
void ikcp_update(ikcpcb *kcp, IUINT32 current)
|
|
1239
|
+
{
|
|
1240
|
+
IINT32 slap;
|
|
1241
|
+
|
|
1242
|
+
kcp->current = current;
|
|
1243
|
+
|
|
1244
|
+
if (kcp->updated == 0) {
|
|
1245
|
+
kcp->updated = 1;
|
|
1246
|
+
kcp->ts_flush = kcp->current;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
slap = _itimediff(kcp->current, kcp->ts_flush);
|
|
1250
|
+
|
|
1251
|
+
if (slap >= 10000 || slap < -10000) {
|
|
1252
|
+
kcp->ts_flush = kcp->current;
|
|
1253
|
+
slap = 0;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
if (slap >= 0) {
|
|
1257
|
+
kcp->ts_flush += kcp->interval;
|
|
1258
|
+
if (_itimediff(kcp->current, kcp->ts_flush) >= 0) {
|
|
1259
|
+
kcp->ts_flush = kcp->current + kcp->interval;
|
|
1260
|
+
}
|
|
1261
|
+
ikcp_flush(kcp);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
//---------------------------------------------------------------------
|
|
1267
|
+
// Determines when you should invoke ikcp_update next:
|
|
1268
|
+
// returns the timestamp (in milliseconds) at which you should call
|
|
1269
|
+
// ikcp_update, assuming no ikcp_input/_send calls occur in between.
|
|
1270
|
+
// You can call ikcp_update at that time instead of calling it repeatedly.
|
|
1271
|
+
// Important for reducing unnecessary ikcp_update invocations. Use it to
|
|
1272
|
+
// schedule ikcp_update (e.g., implementing an epoll-like mechanism,
|
|
1273
|
+
// or optimizing ikcp_update when handling massive kcp connections).
|
|
1274
|
+
//---------------------------------------------------------------------
|
|
1275
|
+
IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current)
|
|
1276
|
+
{
|
|
1277
|
+
IUINT32 ts_flush = kcp->ts_flush;
|
|
1278
|
+
IINT32 tm_flush = 0x7fffffff;
|
|
1279
|
+
IINT32 tm_packet = 0x7fffffff;
|
|
1280
|
+
IUINT32 minimal = 0;
|
|
1281
|
+
struct IQUEUEHEAD *p;
|
|
1282
|
+
|
|
1283
|
+
if (kcp->updated == 0) {
|
|
1284
|
+
return current;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
if (_itimediff(current, ts_flush) >= 10000 ||
|
|
1288
|
+
_itimediff(current, ts_flush) < -10000) {
|
|
1289
|
+
ts_flush = current;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
if (_itimediff(current, ts_flush) >= 0) {
|
|
1293
|
+
return current;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
tm_flush = _itimediff(ts_flush, current);
|
|
1297
|
+
|
|
1298
|
+
for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) {
|
|
1299
|
+
const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node);
|
|
1300
|
+
IINT32 diff = _itimediff(seg->resendts, current);
|
|
1301
|
+
if (diff <= 0) {
|
|
1302
|
+
return current;
|
|
1303
|
+
}
|
|
1304
|
+
if (diff < tm_packet) tm_packet = diff;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
minimal = (IUINT32)(tm_packet < tm_flush ? tm_packet : tm_flush);
|
|
1308
|
+
if (minimal >= kcp->interval) minimal = kcp->interval;
|
|
1309
|
+
|
|
1310
|
+
return current + minimal;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
int ikcp_setmtu(ikcpcb *kcp, int mtu)
|
|
1316
|
+
{
|
|
1317
|
+
char *buffer;
|
|
1318
|
+
if (mtu < 50 || mtu < (int)IKCP_OVERHEAD)
|
|
1319
|
+
return -1;
|
|
1320
|
+
buffer = (char*)ikcp_malloc((mtu + IKCP_OVERHEAD) * 3);
|
|
1321
|
+
if (buffer == NULL)
|
|
1322
|
+
return -2;
|
|
1323
|
+
kcp->mtu = mtu;
|
|
1324
|
+
kcp->mss = kcp->mtu - IKCP_OVERHEAD;
|
|
1325
|
+
ikcp_free(kcp->buffer);
|
|
1326
|
+
kcp->buffer = buffer;
|
|
1327
|
+
return 0;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
int ikcp_interval(ikcpcb *kcp, int interval)
|
|
1331
|
+
{
|
|
1332
|
+
if (interval > 5000) interval = 5000;
|
|
1333
|
+
else if (interval < 10) interval = 10;
|
|
1334
|
+
kcp->interval = interval;
|
|
1335
|
+
return 0;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc)
|
|
1339
|
+
{
|
|
1340
|
+
if (nodelay >= 0) {
|
|
1341
|
+
kcp->nodelay = nodelay;
|
|
1342
|
+
if (nodelay) {
|
|
1343
|
+
kcp->rx_minrto = IKCP_RTO_NDL;
|
|
1344
|
+
}
|
|
1345
|
+
else {
|
|
1346
|
+
kcp->rx_minrto = IKCP_RTO_MIN;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
if (interval >= 0) {
|
|
1350
|
+
if (interval > 5000) interval = 5000;
|
|
1351
|
+
else if (interval < 10) interval = 10;
|
|
1352
|
+
kcp->interval = interval;
|
|
1353
|
+
}
|
|
1354
|
+
if (resend >= 0) {
|
|
1355
|
+
kcp->fastresend = resend;
|
|
1356
|
+
}
|
|
1357
|
+
if (nc >= 0) {
|
|
1358
|
+
kcp->nocwnd = nc;
|
|
1359
|
+
}
|
|
1360
|
+
return 0;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
|
|
1364
|
+
int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd)
|
|
1365
|
+
{
|
|
1366
|
+
if (kcp) {
|
|
1367
|
+
if (sndwnd > 0) {
|
|
1368
|
+
kcp->snd_wnd = sndwnd;
|
|
1369
|
+
}
|
|
1370
|
+
if (rcvwnd > 0) { // must >= max fragment size
|
|
1371
|
+
kcp->rcv_wnd = _imax_(rcvwnd, IKCP_WND_RCV);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return 0;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
int ikcp_waitsnd(const ikcpcb *kcp)
|
|
1378
|
+
{
|
|
1379
|
+
return kcp->nsnd_buf + kcp->nsnd_que;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
// read conv
|
|
1384
|
+
IUINT32 ikcp_getconv(const void *ptr)
|
|
1385
|
+
{
|
|
1386
|
+
IUINT32 conv;
|
|
1387
|
+
ikcp_decode32u((const char*)ptr, &conv);
|
|
1388
|
+
return conv;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
//---------------------------------------------------------------------
|
|
1393
|
+
// install congestion control
|
|
1394
|
+
//---------------------------------------------------------------------
|
|
1395
|
+
int ikcp_setcc(ikcpcb *kcp, const struct IKCPOPS *ops)
|
|
1396
|
+
{
|
|
1397
|
+
assert(kcp);
|
|
1398
|
+
if (kcp->ccops && kcp->ccops->release) {
|
|
1399
|
+
kcp->ccops->release(kcp);
|
|
1400
|
+
}
|
|
1401
|
+
kcp->congest = NULL;
|
|
1402
|
+
kcp->ccops = ops;
|
|
1403
|
+
if (ops) {
|
|
1404
|
+
if (ops->init) {
|
|
1405
|
+
if (ops->init(kcp) < 0) {
|
|
1406
|
+
kcp->ccops = NULL;
|
|
1407
|
+
kcp->congest = NULL;
|
|
1408
|
+
if (kcp->cwnd < 1) kcp->cwnd = 1;
|
|
1409
|
+
kcp->incr = kcp->cwnd * kcp->mss;
|
|
1410
|
+
return -1;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
else {
|
|
1415
|
+
if (kcp->cwnd < 1) kcp->cwnd = 1;
|
|
1416
|
+
kcp->incr = kcp->cwnd * kcp->mss;
|
|
1417
|
+
if (kcp->incr < kcp->mss) kcp->incr = kcp->mss;
|
|
1418
|
+
}
|
|
1419
|
+
return 0;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
|