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
42int 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
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/* ウィンドウ内インデックス計算 */
126static 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
141int 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
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
202int 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
242int 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
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
313void 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
336int 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
378void 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}
#define POTR_SUCCESS
成功の戻り値を表す定数。
#define POTR_ERROR
失敗の戻り値を表す定数。
通信ライブラリの定数ファイル。
int seqnum_in_window(uint32_t seq, uint32_t base, uint16_t window_size)
通番 seq がウィンドウ [base, base + window_size) に含まれるか判定します。
Definition seqnum.c:80
通番管理モジュールの内部ヘッダー。
ネットワーク送受信用パケット構造体。
const uint8_t * payload
ペイロードデータへのポインタ (読み取り専用)。ウィンドウプールまたは受信バッファ内を指す。
uint32_t seq_num
通番。送信側が付与する連番 (NBO)。
uint16_t payload_len
ペイロード長 (バイト) (NBO)。
スライディングウィンドウ管理構造体。
Definition window.h:30
uint32_t base_seq
ウィンドウ先頭の通番。
Definition window.h:34
uint16_t max_payload
エントリごとのペイロード最大長 (バイト)。
Definition window.h:37
uint32_t next_seq
送信側: 次に割り当てる通番。受信側: 次に期待する通番。
Definition window.h:35
uint8_t * payload_pool
ペイロードプール (動的確保。window_size × max_payload バイト)。
Definition window.h:33
uint8_t * valid
バッファ有効フラグ配列 (動的確保。window_size バイト)。
Definition window.h:32
PotrPacket * packets
パケットバッファ (動的確保。window_size 要素)。
Definition window.h:31
uint16_t window_size
ウィンドウサイズ (パケット数)。
Definition window.h:36
void window_recv_skip(PotrWindow *win, uint32_t seq_num)
受信ウィンドウで指定通番をスキップして次の通番へ前進させます。
Definition window.c:313
int window_send_push(PotrWindow *win, const PotrPacket *packet)
送信ウィンドウにパケットを積みます。
Definition window.c:141
int window_init(PotrWindow *win, uint32_t initial_seq, uint16_t window_size, uint16_t max_payload)
ウィンドウを初期化します。
Definition window.c:42
void window_destroy(PotrWindow *win)
ウィンドウが保持する動的確保バッファを解放します。
Definition window.c:110
int window_recv_needs_nack(const PotrWindow *win, uint32_t *nack_num)
受信ウィンドウで欠番が発生しているか確認し、NACK 番号を返します。
Definition window.c:336
void window_recv_reset(PotrWindow *win, uint32_t new_base_seq)
受信ウィンドウを新しい基点通番でリセットします。
Definition window.c:378
int window_send_get(const PotrWindow *win, uint32_t seq_num, PotrPacket *packet_out)
送信ウィンドウから指定通番のパケットを取得します (再送用)。
Definition window.c:202
int window_recv_pop(PotrWindow *win, PotrPacket *packet)
受信ウィンドウから順序整列済みパケットを取り出します。
Definition window.c:279
int window_send_full(const PotrWindow *win)
送信ウィンドウが満杯かどうかを返します。
Definition window.c:184
int window_recv_push(PotrWindow *win, const PotrPacket *packet)
受信ウィンドウにパケットを格納します。
Definition window.c:242
static uint16_t win_index(const PotrWindow *win, uint32_t seq)
Definition window.c:126
スライディングウィンドウ管理モジュールの内部ヘッダー。