|
1 | 1 | package enet
|
2 | 2 |
|
3 | 3 | const channel_wnd_size = 256
|
4 |
| -const enet_channel_id_none uint8 = 0xff |
5 | 4 |
|
| 5 | +type enet_channel_item struct { |
| 6 | + header enet_packet_header |
| 7 | + fragment enet_packet_fragment // if header.cmd == enet_packet_fragment |
| 8 | + payload []uint8 // not include packet-header |
| 9 | + retries int // sent times for outgoing packet, acked times for incoming packet |
| 10 | + acked int // acked times |
| 11 | + retrans *enet_timer_item // retrans timer |
| 12 | +} |
| 13 | + |
| 14 | +// outgoing: ->end ..untransfered.. next ..transfered.. begin -> |
| 15 | +// incoming: <-begin ..acked.. next ..unacked.. end<- |
6 | 16 | type enet_channel struct {
|
7 |
| - _out_sn uint16 |
8 |
| - _out_usn uint16 |
9 |
| - expected_sn uint16 |
10 |
| - expected_usn uint16 |
11 |
| - wnd [channel_wnd_size]uint16 |
12 |
| - wnd_used int |
13 |
| - last_acked uint16 |
14 |
| - last_intrans uint16 |
| 17 | + next_sn uint32 // next reliable packet number for sent |
| 18 | + next_usn uint32 // next unsequenced packet number for sent |
| 19 | + outgoing [channel_wnd_size]*enet_channel_item |
| 20 | + outgoing_used uint32 // in trans packets not acked |
| 21 | + outgoing_begin uint32 // the first one is not acked yet |
| 22 | + outgoing_end uint32 // the last one is not acked yet |
| 23 | + outgoing_next uint32 // the next one would be transfered |
| 24 | + incoming [channel_wnd_size]*enet_channel_item |
| 25 | + incoming_used uint32 // rcvd packet count in incoming window |
| 26 | + incoming_begin uint32 // the first one has be received |
| 27 | + incoming_end uint32 // the last one has been received |
| 28 | + // incoming_next uint32 // the next one will be acked |
15 | 29 | }
|
16 | 30 |
|
17 |
| -func (ch enet_channel) wnd_is_full() bool { |
18 |
| - return ch.wnd_used >= channel_wnd_size |
| 31 | +func (ch *enet_channel) outgoing_trans(item *enet_channel_item) { |
| 32 | + idx := item.header.sn % channel_wnd_size |
| 33 | + v := ch.outgoing[idx] |
| 34 | + assert(v == nil && item.header.sn == ch.outgoing_end) |
| 35 | + ch.outgoing[idx] = item |
| 36 | + if ch.outgoing_end <= item.header.sn { |
| 37 | + ch.outgoing_end = item.header.sn + 1 |
| 38 | + } |
| 39 | + item.retries++ |
| 40 | + ch.outgoing_used++ |
19 | 41 | }
|
20 | 42 |
|
21 |
| -func (ch *enet_channel) wnd_put_in(sn uint16) { |
| 43 | +func (ch *enet_channel) outgoing_ack(sn uint32) { |
| 44 | + if sn < ch.outgoing_begin || sn >= ch.outgoing_end { // already acked or error |
| 45 | + return |
| 46 | + } |
22 | 47 | idx := sn % channel_wnd_size
|
23 |
| - v := ch.wnd[idx] |
24 |
| - if v == 0 { |
25 |
| - ch.wnd_used++ |
26 |
| - ch.last_intrans = sn |
| 48 | + v := ch.outgoing[idx] |
| 49 | + assert(v != nil && v.header.sn == sn) |
| 50 | + |
| 51 | + v.acked++ |
| 52 | +} |
| 53 | + |
| 54 | +func (ch *enet_channel) outgoing_do_trans() (item *enet_channel_item) { |
| 55 | + assert(ch.outgoing_next <= ch.outgoing_end) |
| 56 | + if ch.outgoing_next >= ch.outgoing_end { |
| 57 | + return |
27 | 58 | }
|
28 |
| - ch.wnd[idx]++ |
| 59 | + idx := ch.outgoing_next % channel_wnd_size |
| 60 | + item = ch.outgoing[idx] |
| 61 | + assert(item != nil) |
| 62 | + ch.outgoing_next++ |
| 63 | + return |
29 | 64 | }
|
30 | 65 |
|
31 |
| -func (ch *enet_channel) wnd_pop_out(sn uint16) { |
32 |
| - idx := sn % channel_wnd_size |
33 |
| - v := ch.wnd[idx] |
34 |
| - if v <= 0 { |
| 66 | +// may be retransed packet |
| 67 | +func (ch *enet_channel) incoming_trans(item *enet_channel_item) { |
| 68 | + if item.header.sn < ch.incoming_begin { |
| 69 | + return |
| 70 | + } |
| 71 | + idx := item.header.sn % channel_wnd_size |
| 72 | + v := ch.incoming[idx] |
| 73 | + // duplicated packet |
| 74 | + if v != nil { |
35 | 75 | return
|
36 | 76 | }
|
37 |
| - ch.wnd_used-- |
38 |
| - ch.wnd[idx] = 0 |
39 |
| - ch.last_acked = sn |
| 77 | + assert(v == nil || v.header.sn == item.header.sn) |
| 78 | + |
| 79 | + ch.incoming[idx] = item |
| 80 | + ch.incoming_used++ |
| 81 | + if ch.incoming_end <= item.header.sn { |
| 82 | + ch.incoming_end = item.header.sn + 1 |
| 83 | + } |
40 | 84 | }
|
41 |
| -func (ch *enet_channel) out_sn() uint16 { |
42 |
| - v := ch._out_sn |
43 |
| - ch._out_sn++ |
44 |
| - return v |
| 85 | + |
| 86 | +// when do ack incoming packets |
| 87 | +func (ch *enet_channel) incoming_ack(sn uint32) { |
| 88 | + if sn < ch.incoming_begin || sn >= ch.incoming_end { // reack packet not in wnd |
| 89 | + return |
| 90 | + } |
| 91 | + idx := sn % channel_wnd_size |
| 92 | + v := ch.incoming[idx] |
| 93 | + assert(v != nil && v.header.sn == sn) |
| 94 | + v.acked++ |
| 95 | +} |
| 96 | + |
| 97 | +// called after incoming-ack |
| 98 | +func (ch *enet_channel) incoming_slide() (item *enet_channel_item) { // return value may be ignored |
| 99 | + if ch.incoming_begin >= ch.incoming_end { |
| 100 | + return |
| 101 | + } |
| 102 | + idx := ch.incoming_begin % channel_wnd_size |
| 103 | + v := ch.incoming[idx] |
| 104 | + if v == nil || v.acked <= 0 { // not received yet |
| 105 | + return |
| 106 | + } |
| 107 | + assert(v.header.sn == ch.incoming_begin) |
| 108 | + |
| 109 | + if v.header.cmd == enet_packet_type_fragment { |
| 110 | + all := true |
| 111 | + for i := uint32(1); i < v.fragment.count; i++ { |
| 112 | + n := ch.incoming[idx+i] |
| 113 | + if n == nil || n.header.sn != v.header.sn+i || n.fragment.sn != v.header.sn { |
| 114 | + all = false |
| 115 | + break |
| 116 | + } |
| 117 | + } |
| 118 | + if !all { |
| 119 | + return |
| 120 | + } |
| 121 | + |
| 122 | + item = v |
| 123 | + ch.incoming_begin += v.fragment.count |
| 124 | + ch.incoming_used -= v.fragment.count |
| 125 | + for i := uint32(1); i < v.fragment.count; i++ { |
| 126 | + item.payload = append(item.payload, ch.incoming[idx+1].payload...) |
| 127 | + ch.incoming[idx+i] = nil |
| 128 | + } |
| 129 | + ch.incoming[idx] = nil |
| 130 | + |
| 131 | + return |
| 132 | + } |
| 133 | + item = v |
| 134 | + ch.incoming_begin++ |
| 135 | + ch.incoming_used-- |
| 136 | + ch.incoming[idx] = nil |
| 137 | + return |
45 | 138 | }
|
46 | 139 |
|
47 |
| -func (ch *enet_channel) out_usn() uint16 { |
48 |
| - v := ch._out_usn |
49 |
| - ch._out_usn++ |
50 |
| - return v |
| 140 | +func (ch enet_channel) is_outgoing_full() bool { |
| 141 | + return ch.outgoing_end-ch.outgoing_begin >= channel_wnd_size |
| 142 | +} |
| 143 | +func (ch enet_channel) is_incoming_full() bool { |
| 144 | + return ch.incoming_end-ch.incoming_begin >= channel_wnd_size |
| 145 | +} |
| 146 | +func (ch enet_channel) is_outgoing_null() bool { |
| 147 | + return ch.outgoing_end <= ch.outgoing_begin |
| 148 | +} |
| 149 | +func (ch enet_channel) is_incoming_null() bool { |
| 150 | + return ch.incoming_end <= ch.incoming_begin |
| 151 | +} |
| 152 | +func (ch enet_channel) outgoing_intrans() int { |
| 153 | + return int(ch.outgoing_next - ch.outgoing_begin) |
51 | 154 | }
|
0 commit comments