Document of c-modernization-kit (porter) 1.0.0

Loading...
Searching...
No Matches
window.c
Go to the documentation of this file.
1
13
14#include <stdlib.h>
15#include <string.h>
16
17#ifndef _WIN32
18 #include <arpa/inet.h>
19#else /* _WIN32 */
20 #include <winsock2.h>
21#endif /* _WIN32 */
22
23#include <porter_const.h>
24
25#include "seqnum.h"
26#include "window.h"
27
42 int window_init(PotrWindow *win, uint32_t initial_seq,
43 uint16_t window_size, uint16_t max_payload)
44{
45 uint16_t i;
46
47 if (win == NULL)
48 {
49 return POTR_ERROR;
50 }
51
52 /* 既存バッファがあり、サイズが一致する場合は状態リセットのみ */
53 if (win->packets != NULL
54 && win->window_size == window_size
55 && win->max_payload == max_payload)
56 {
57 memset(win->valid, 0, window_size);
58 win->base_seq = initial_seq;
59 win->next_seq = initial_seq;
60 return POTR_SUCCESS;
61 }
62
63 /* 既存バッファを解放 */
64 free(win->packets);
65 free(win->valid);
66 free(win->payload_pool);
67 win->packets = NULL;
68 win->valid = NULL;
69 win->payload_pool = NULL;
70
71 /* 新規確保 */
72 win->packets = (PotrPacket *)malloc((size_t)window_size * sizeof(PotrPacket));
73 win->valid = (uint8_t *)malloc((size_t)window_size);
74 win->payload_pool = (uint8_t *)malloc((size_t)window_size * (size_t)max_payload);
75
76 if (win->packets == NULL || win->valid == NULL || win->payload_pool == NULL)
77 {
78 free(win->packets);
79 free(win->valid);
80 free(win->payload_pool);
81 win->packets = NULL;
82 win->valid = NULL;
83 win->payload_pool = NULL;
84 return POTR_ERROR;
85 }
86
87 memset(win->valid, 0, (size_t)window_size);
88
89 /* 各エントリの payload ポインタをプールスロットへ設定 */
90 for (i = 0; i < window_size; i++)
91 {
92 memset(&win->packets[i], 0, sizeof(PotrPacket));
93 win->packets[i].payload = win->payload_pool + (size_t)i * (size_t)max_payload;
94 }
95
96 win->base_seq = initial_seq;
97 win->next_seq = initial_seq;
98 win->window_size = window_size;
99 win->max_payload = max_payload;
100
101 return POTR_SUCCESS;
102}
103
110 void window_destroy(PotrWindow *win)
111{
112 if (win == NULL)
113 {
114 return;
115 }
116
117 free(win->packets);
118 free(win->valid);
119 free(win->payload_pool);
120 win->packets = NULL;
121 win->valid = NULL;
122 win->payload_pool = NULL;
123}
124
125/* ウィンドウ内インデックス計算 */
126 static uint16_t win_index(const PotrWindow *win, uint32_t seq)
127{
128 return (uint16_t)((seq - win->base_seq) % win->window_size);
129}
130
131/* ---------- 送信側 ---------- */
132
141 int window_send_push(PotrWindow *win, const PotrPacket *packet)
142{
143 uint16_t idx;
144
145 if (win == NULL || packet == NULL)
146 {
147 return POTR_ERROR;
148 }
149
150 /* ACK なし設計のため、満杯の場合は最古エントリを evict して循環利用する。
151 evict されたエントリへの NACK は REJECT で応答する。 */
152 if (window_send_full(win))
153 {
154 idx = win_index(win, win->base_seq);
155 win->valid[idx] = 0;
156 win->base_seq++;
157 }
158
159 idx = win_index(win, win->next_seq);
160
161 /* プールスロットへ深コピー (packet->payload_len は NBO: packet_build_packed が設定) */
162 {
163 /* プールスロットアドレスをインデックスから直接計算することで const 除去キャストを回避する */
164 uint8_t *slot = win->payload_pool + idx * (size_t)win->max_payload;
165 win->packets[idx] = *packet; /* 構造体コピー */
166 win->packets[idx].payload = slot; /* プールスロットを設定 */
167 memcpy(slot, packet->payload, (size_t)ntohs(packet->payload_len));
168 }
169
170 win->valid[idx] = 1;
171 win->next_seq++;
172
173 return POTR_SUCCESS;
174}
175
176
184 int window_send_full(const PotrWindow *win)
185{
186 if (win == NULL)
187 {
188 return 1;
189 }
190 return (uint32_t)(win->next_seq - win->base_seq) >= (uint32_t)win->window_size;
191}
192
202 int window_send_get(const PotrWindow *win, uint32_t seq_num, PotrPacket *packet_out)
203{
204 uint16_t idx;
205
206 if (win == NULL || packet_out == NULL)
207 {
208 return POTR_ERROR;
209 }
210
211 /* 通番がウィンドウ範囲外 */
212 if (!seqnum_in_window(seq_num, win->base_seq,
213 (uint16_t)(win->next_seq - win->base_seq)))
214 {
215 return POTR_ERROR;
216 }
217
218 idx = win_index(win, seq_num);
219 if (!win->valid[idx])
220 {
221 return POTR_ERROR;
222 }
223
224 *packet_out = win->packets[idx];
225 return POTR_SUCCESS;
226}
227
228/* ---------- 受信側 ---------- */
229
242 int window_recv_push(PotrWindow *win, const PotrPacket *packet)
243{
244 uint16_t idx;
245
246 if (win == NULL || packet == NULL)
247 {
248 return POTR_ERROR;
249 }
250
251 if (!seqnum_in_window(packet->seq_num, win->base_seq, win->window_size))
252 {
253 return POTR_ERROR;
254 }
255
256 idx = win_index(win, packet->seq_num);
257 if (!win->valid[idx])
258 {
259 /* プールスロットへ深コピー (packet->payload_len はホストバイトオーダー: packet_parse が変換済み) */
260 /* プールスロットアドレスをインデックスから直接計算することで const 除去キャストを回避する */
261 uint8_t *slot = win->payload_pool + idx * (size_t)win->max_payload;
262 win->packets[idx] = *packet;
263 win->packets[idx].payload = slot;
264 memcpy(slot, packet->payload, (size_t)packet->payload_len);
265 win->valid[idx] = 1;
266 }
267
268 return POTR_SUCCESS;
269}
270
279 int window_recv_pop(PotrWindow *win, PotrPacket *packet)
280{
281 uint16_t idx;
282
283 if (win == NULL || packet == NULL)
284 {
285 return POTR_ERROR;
286 }
287
288 idx = win_index(win, win->next_seq);
289 if (!win->valid[idx])
290 {
291 return POTR_ERROR;
292 }
293
294 *packet = win->packets[idx];
295 win->valid[idx] = 0;
296 win->base_seq++;
297 win->next_seq++;
298
299 return POTR_SUCCESS;
300}
301
313 void window_recv_skip(PotrWindow *win, uint32_t seq_num)
314{
315 uint16_t idx;
316
317 if (win == NULL || win->next_seq != seq_num)
318 {
319 return;
320 }
321
322 idx = win_index(win, seq_num);
323 win->valid[idx] = 0; /* 万一セットされていても無効化 */
324 win->base_seq++;
325 win->next_seq++;
326}
327
336 int window_recv_needs_nack(const PotrWindow *win, uint32_t *nack_num)
337{
338 uint16_t i;
339 uint16_t idx;
340
341 if (win == NULL || nack_num == NULL)
342 {
343 return 0;
344 }
345
346 idx = win_index(win, win->next_seq);
347 if (win->valid[idx])
348 {
349 return 0; /* next_seq が既着 = 欠番なし */
350 }
351
352 /* next_seq が未着のとき、ウィンドウ内に先行して到着したパケットがあれば欠番 */
353 for (i = 1U; i < win->window_size; i++)
354 {
355 uint16_t look_idx = win_index(win, win->next_seq + i);
356 if (win->valid[look_idx])
357 {
358 *nack_num = win->next_seq;
359 return 1;
360 }
361 }
362
363 return 0; /* ウィンドウが空 = 欠番なし */
364}
365
378 void window_recv_reset(PotrWindow *win, uint32_t new_base_seq)
379{
380 if (win == NULL || win->valid == NULL)
381 {
382 return;
383 }
384
385 memset(win->valid, 0, (size_t)win->window_size);
386 win->base_seq = new_base_seq;
387 win->next_seq = new_base_seq;
388}
POTR_SUCCESS
#define POTR_SUCCESS
成功の戻り値を表す定数。
Definition porter_const.h:30
POTR_ERROR
#define POTR_ERROR
失敗の戻り値を表す定数。
Definition porter_const.h:31
porter_const.h
通信ライブラリの定数ファイル。
seqnum_in_window
int seqnum_in_window(uint32_t seq, uint32_t base, uint16_t window_size)
通番 seq がウィンドウ [base, base + window_size) に含まれるか判定します。
Definition seqnum.c:80
seqnum.h
通番管理モジュールの内部ヘッダー。
PotrPacket
ネットワーク送受信用パケット構造体。
Definition porter_type.h:216
PotrPacket::payload
const uint8_t * payload
ペイロードデータへのポインタ (読み取り専用)。ウィンドウプールまたは受信バッファ内を指す。
Definition porter_type.h:226
PotrPacket::seq_num
uint32_t seq_num
通番。送信側が付与する連番 (NBO)。
Definition porter_type.h:221
PotrPacket::payload_len
uint16_t payload_len
ペイロード長 (バイト) (NBO)。
Definition porter_type.h:224
PotrWindow
スライディングウィンドウ管理構造体。
Definition window.h:30
PotrWindow::base_seq
uint32_t base_seq
ウィンドウ先頭の通番。
Definition window.h:34
PotrWindow::max_payload
uint16_t max_payload
エントリごとのペイロード最大長 (バイト)。
Definition window.h:37
PotrWindow::next_seq
uint32_t next_seq
送信側: 次に割り当てる通番。受信側: 次に期待する通番。
Definition window.h:35
PotrWindow::payload_pool
uint8_t * payload_pool
ペイロードプール (動的確保。window_size × max_payload バイト)。
Definition window.h:33
PotrWindow::valid
uint8_t * valid
バッファ有効フラグ配列 (動的確保。window_size バイト)。
Definition window.h:32
PotrWindow::packets
PotrPacket * packets
パケットバッファ (動的確保。window_size 要素)。
Definition window.h:31
PotrWindow::window_size
uint16_t window_size
ウィンドウサイズ (パケット数)。
Definition window.h:36
window_recv_skip
void window_recv_skip(PotrWindow *win, uint32_t seq_num)
受信ウィンドウで指定通番をスキップして次の通番へ前進させます。
Definition window.c:313
window_send_push
int window_send_push(PotrWindow *win, const PotrPacket *packet)
送信ウィンドウにパケットを積みます。
Definition window.c:141
window_init
int window_init(PotrWindow *win, uint32_t initial_seq, uint16_t window_size, uint16_t max_payload)
ウィンドウを初期化します。
Definition window.c:42
window_destroy
void window_destroy(PotrWindow *win)
ウィンドウが保持する動的確保バッファを解放します。
Definition window.c:110
window_recv_needs_nack
int window_recv_needs_nack(const PotrWindow *win, uint32_t *nack_num)
受信ウィンドウで欠番が発生しているか確認し、NACK 番号を返します。
Definition window.c:336
window_recv_reset
void window_recv_reset(PotrWindow *win, uint32_t new_base_seq)
受信ウィンドウを新しい基点通番でリセットします。
Definition window.c:378
window_send_get
int window_send_get(const PotrWindow *win, uint32_t seq_num, PotrPacket *packet_out)
送信ウィンドウから指定通番のパケットを取得します (再送用)。
Definition window.c:202
window_recv_pop
int window_recv_pop(PotrWindow *win, PotrPacket *packet)
受信ウィンドウから順序整列済みパケットを取り出します。
Definition window.c:279
window_send_full
int window_send_full(const PotrWindow *win)
送信ウィンドウが満杯かどうかを返します。
Definition window.c:184
window_recv_push
int window_recv_push(PotrWindow *win, const PotrPacket *packet)
受信ウィンドウにパケットを格納します。
Definition window.c:242
win_index
static uint16_t win_index(const PotrWindow *win, uint32_t seq)
Definition window.c:126
window.h
スライディングウィンドウ管理モジュールの内部ヘッダー。