Document of c-modernization-kit (porter) 1.0.0

Loading...
Searching...
No Matches
packet.c
Go to the documentation of this file.
1
13
14#include <stddef.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#include <porter_type.h>
25
26#include "packet.h"
27
28/* packet.h で公開した PACKET_HEADER_SIZE をそのまま使用する */
29
30/* 64 ビット値をホストバイトオーダーからネットワークバイトオーダーへ変換する */
31 static uint64_t hton64(uint64_t v)
32{
33 uint32_t hi = htonl((uint32_t)(v >> 32));
34 uint32_t lo = htonl((uint32_t)(v & 0xFFFFFFFFUL));
35 return ((uint64_t)lo << 32) | (uint64_t)hi;
36}
37
38/* 64 ビット値をネットワークバイトオーダーからホストバイトオーダーへ変換する */
39 static uint64_t ntoh64(uint64_t v)
40{
41 return hton64(v); /* 対称変換 */
42}
43
44/* セッションヘッダーフィールドをパケットに NBO で書き込む */
45 static void fill_session_hdr(PotrPacket *packet, const PotrPacketSessionHdr *shdr)
46{
47 packet->service_id = (int64_t)hton64((uint64_t)shdr->service_id);
48 packet->session_tv_sec = (int64_t)hton64((uint64_t)shdr->session_tv_sec);
49 packet->session_id = htonl(shdr->session_id);
50 packet->session_tv_nsec = htonl((uint32_t)shdr->session_tv_nsec);
51}
52
62 int packet_build_nack(PotrPacket *packet, const PotrPacketSessionHdr *shdr,
63 uint32_t nack_num)
64{
65 if (packet == NULL || shdr == NULL)
66 {
67 return POTR_ERROR;
68 }
69
70 memset(packet, 0, PACKET_HEADER_SIZE);
71 packet->payload = NULL;
72 fill_session_hdr(packet, shdr);
73 packet->seq_num = 0;
74 packet->ack_num = htonl(nack_num);
75 packet->flags = htons(POTR_FLAG_NACK);
76 packet->payload_len = 0;
77
78 return POTR_SUCCESS;
79}
80
99 int packet_build_ping(PotrPacket *packet, const PotrPacketSessionHdr *shdr,
100 uint32_t seq_num, uint32_t ack_num)
101{
102 if (packet == NULL || shdr == NULL)
103 {
104 return POTR_ERROR;
105 }
106
107 memset(packet, 0, PACKET_HEADER_SIZE);
108 packet->payload = NULL;
109 fill_session_hdr(packet, shdr);
110 packet->seq_num = htonl(seq_num);
111 packet->ack_num = htonl(ack_num);
112 packet->flags = htons(POTR_FLAG_PING);
113 packet->payload_len = 0;
114
115 return POTR_SUCCESS;
116}
117
132 int packet_build_reject(PotrPacket *packet, const PotrPacketSessionHdr *shdr,
133 uint32_t seq_num)
134{
135 if (packet == NULL || shdr == NULL)
136 {
137 return POTR_ERROR;
138 }
139
140 memset(packet, 0, PACKET_HEADER_SIZE);
141 packet->payload = NULL;
142 fill_session_hdr(packet, shdr);
143 packet->seq_num = 0;
144 packet->ack_num = htonl(seq_num);
145 packet->flags = htons(POTR_FLAG_REJECT);
146 packet->payload_len = 0;
147
148 return POTR_SUCCESS;
149}
150
163 int packet_build_fin(PotrPacket *packet, const PotrPacketSessionHdr *shdr)
164{
165 if (packet == NULL || shdr == NULL)
166 {
167 return POTR_ERROR;
168 }
169
170 memset(packet, 0, PACKET_HEADER_SIZE);
171 packet->payload = NULL;
172 fill_session_hdr(packet, shdr);
173 packet->seq_num = 0;
174 packet->ack_num = 0;
175 packet->flags = htons(POTR_FLAG_FIN);
176 packet->payload_len = 0;
177
178 return POTR_SUCCESS;
179}
180
200 int packet_build_packed(PotrPacket *out, const PotrPacketSessionHdr *shdr,
201 uint32_t seq_num,
202 const void *packed_payload, size_t payload_len)
203{
204 if (out == NULL || shdr == NULL || packed_payload == NULL
205 || payload_len == 0 || payload_len > POTR_MAX_PAYLOAD)
206 {
207 return POTR_ERROR;
208 }
209
210 memset(out, 0, PACKET_HEADER_SIZE);
211 fill_session_hdr(out, shdr);
212 out->seq_num = htonl(seq_num);
213 out->ack_num = 0;
214 out->flags = htons(POTR_FLAG_DATA);
215 out->payload_len = htons((uint16_t)payload_len);
216 /* ゼロコピー: 呼び出し元バッファを直接指す。 */
217 out->payload = (const uint8_t *)packed_payload;
218
219 return POTR_SUCCESS;
220}
221
238 int packet_unpack_next(const PotrPacket *container, size_t *offset,
239 PotrPacket *elem_out)
240{
241 const uint8_t *p;
242 uint16_t flags_nbo;
243 uint32_t plen_nbo;
244 uint32_t payload_len;
245
246 if (container == NULL || offset == NULL || elem_out == NULL)
247 {
248 return POTR_ERROR;
249 }
250
251 /* 末尾チェック (container->payload_len はホストバイトオーダー) */
252 if (*offset + POTR_PAYLOAD_ELEM_HDR_SIZE > (size_t)container->payload_len)
253 {
254 return POTR_ERROR;
255 }
256
257 p = container->payload + *offset;
258
259 memcpy(&flags_nbo, p, 2);
260 memcpy(&plen_nbo, p + 2, 4);
261
262 payload_len = ntohl(plen_nbo);
263
264 if (*offset + POTR_PAYLOAD_ELEM_HDR_SIZE + payload_len > (size_t)container->payload_len
265 || payload_len > POTR_MAX_PAYLOAD)
266 {
267 return POTR_ERROR;
268 }
269
270 memset(elem_out, 0, PACKET_HEADER_SIZE);
271 elem_out->payload = NULL;
272 elem_out->service_id = container->service_id;
273 elem_out->session_id = container->session_id;
274 elem_out->session_tv_sec = container->session_tv_sec;
275 elem_out->session_tv_nsec = container->session_tv_nsec;
276 elem_out->ack_num = 0;
277 elem_out->flags = ntohs(flags_nbo);
278 elem_out->payload_len = (uint16_t)payload_len;
279 /* ゼロコピー: コンテナのペイロード領域を直接指す。
280 コンテナの生存期間中 (呼び出し元の処理完了まで) のみ有効。 */
281 elem_out->payload = p + POTR_PAYLOAD_ELEM_HDR_SIZE;
282
283 *offset += POTR_PAYLOAD_ELEM_HDR_SIZE + payload_len;
284 return POTR_SUCCESS;
285}
286
299 int packet_parse(PotrPacket *packet, const void *buf, size_t buf_len)
300{
301 const uint8_t *b = (const uint8_t *)buf;
302 uint32_t tmp32;
303 uint64_t tmp64;
304 uint16_t tmp16;
305
306 if (packet == NULL || buf == NULL || buf_len < PACKET_HEADER_SIZE)
307 {
308 return POTR_ERROR;
309 }
310
311 memcpy(&tmp64, b + 0, 8); packet->service_id = (int64_t)ntoh64(tmp64);
312 memcpy(&tmp64, b + 8, 8); packet->session_tv_sec = (int64_t)ntoh64(tmp64);
313 memcpy(&tmp32, b + 16, 4); packet->session_id = ntohl(tmp32);
314 memcpy(&tmp32, b + 20, 4); packet->session_tv_nsec = (int32_t)ntohl(tmp32);
315 memcpy(&tmp32, b + 24, 4); packet->seq_num = ntohl(tmp32);
316 memcpy(&tmp32, b + 28, 4); packet->ack_num = ntohl(tmp32);
317 memcpy(&tmp16, b + 32, 2); packet->flags = ntohs(tmp16);
318 memcpy(&tmp16, b + 34, 2); packet->payload_len = ntohs(tmp16);
319
320 if (packet->payload_len > POTR_MAX_PAYLOAD
321 || (size_t)packet->payload_len + PACKET_HEADER_SIZE > buf_len)
322 {
323 return POTR_ERROR;
324 }
325
326 /* ゼロコピー: 受信バッファ内のペイロード領域を直接指す。
327 呼び出し元バッファ (recv_buf) の生存期間中のみ有効。 */
328 packet->payload = b + PACKET_HEADER_SIZE;
329
330 return POTR_SUCCESS;
331}
332
347 size_t packet_wire_size(const PotrPacket *packet)
348{
349 if (packet == NULL)
350 {
351 return 0;
352 }
353
354 return PACKET_HEADER_SIZE + ntohs(packet->payload_len);
355}
POTR_MAX_PAYLOAD
#define POTR_MAX_PAYLOAD
ペイロードの最大長 (バイト)。UDP 最大ペイロード (65535 - IP20 - UDP8)。max_payload 設定値のバリデーション上限として使用する。
Definition porter_const.h:94
POTR_PAYLOAD_ELEM_HDR_SIZE
#define POTR_PAYLOAD_ELEM_HDR_SIZE
パックコンテナ内ペイロードエレメントのヘッダーサイズ (バイト)。flags (2): POTR_FLAG_MORE_FRAG / POTR_FLAG_COMPRESSED を格納 + payload_...
Definition porter_const.h:99
POTR_FLAG_REJECT
#define POTR_FLAG_REJECT
再送不能通知パケットであることを示すフラグ。ack_num に再送不能な通番を格納する。
Definition porter_const.h:44
POTR_FLAG_PING
#define POTR_FLAG_PING
ヘルスチェック要求パケットであることを示すフラグ。ペイロードなし。
Definition porter_const.h:43
POTR_FLAG_DATA
#define POTR_FLAG_DATA
データパケット (パックコンテナ) であることを示すフラグ。常に設定される。
Definition porter_const.h:41
POTR_FLAG_FIN
#define POTR_FLAG_FIN
正常終了通知パケットであることを示すフラグ。送信者が potrCloseService 時に送出し、受信者は即座に DISCONNECTED へ遷移する。ペイロードなし。
Definition porter_const.h:45
POTR_FLAG_NACK
#define POTR_FLAG_NACK
再送要求パケットであることを示すフラグ。ack_num に要求通番を格納する。
Definition porter_const.h:42
POTR_SUCCESS
#define POTR_SUCCESS
成功の戻り値を表す定数。
Definition porter_const.h:30
POTR_ERROR
#define POTR_ERROR
失敗の戻り値を表す定数。
Definition porter_const.h:31
packet_build_fin
int packet_build_fin(PotrPacket *packet, const PotrPacketSessionHdr *shdr)
正常終了通知 (FIN) パケットを構築します。
Definition packet.c:163
packet_build_packed
int packet_build_packed(PotrPacket *out, const PotrPacketSessionHdr *shdr, uint32_t seq_num, const void *packed_payload, size_t payload_len)
データパケット (パックコンテナ) を構築します。
Definition packet.c:200
packet_build_ping
int packet_build_ping(PotrPacket *packet, const PotrPacketSessionHdr *shdr, uint32_t seq_num, uint32_t ack_num)
PING パケットを構築します。
Definition packet.c:99
packet_parse
int packet_parse(PotrPacket *packet, const void *buf, size_t buf_len)
受信バイト列をパケット構造体に解析します。
Definition packet.c:299
ntoh64
static uint64_t ntoh64(uint64_t v)
Definition packet.c:39
packet_build_nack
int packet_build_nack(PotrPacket *packet, const PotrPacketSessionHdr *shdr, uint32_t nack_num)
NACK パケットを構築します。
Definition packet.c:62
packet_build_reject
int packet_build_reject(PotrPacket *packet, const PotrPacketSessionHdr *shdr, uint32_t seq_num)
再送不能通知 (REJECT) パケットを構築します。
Definition packet.c:132
fill_session_hdr
static void fill_session_hdr(PotrPacket *packet, const PotrPacketSessionHdr *shdr)
Definition packet.c:45
hton64
static uint64_t hton64(uint64_t v)
Definition packet.c:31
packet_unpack_next
int packet_unpack_next(const PotrPacket *container, size_t *offset, PotrPacket *elem_out)
データパケットから次のペイロードエレメントを取り出します。
Definition packet.c:238
packet_wire_size
size_t packet_wire_size(const PotrPacket *packet)
パケットのヘッダー + ペイロードの合計バイト数を返します。
Definition packet.c:347
packet.h
パケット構築・解析モジュールの内部ヘッダー。
PACKET_HEADER_SIZE
#define PACKET_HEADER_SIZE
パケットヘッダーの固定長 (バイト)。payload フィールドの開始オフセット。
Definition packet.h:23
porter_const.h
通信ライブラリの定数ファイル。
porter_type.h
通信ライブラリの型定義ファイル。
PotrPacketSessionHdr
パケットに付与するセッション識別情報。
Definition packet.h:31
PotrPacketSessionHdr::session_tv_nsec
int32_t session_tv_nsec
セッション開始時刻 ナノ秒部。
Definition packet.h:35
PotrPacketSessionHdr::service_id
int64_t service_id
サービス識別子。
Definition packet.h:32
PotrPacketSessionHdr::session_id
uint32_t session_id
セッション識別子 (乱数)。
Definition packet.h:34
PotrPacketSessionHdr::session_tv_sec
int64_t session_tv_sec
セッション開始時刻 秒部。
Definition packet.h:33
PotrPacket
ネットワーク送受信用パケット構造体。
Definition porter_type.h:216
PotrPacket::ack_num
uint32_t ack_num
再送要求番号 / 再送不能通番 (NBO)。NACK では要求通番、REJECT では再送不能通番を格納する。
Definition porter_type.h:222
PotrPacket::session_tv_sec
int64_t session_tv_sec
セッション開始時刻 秒部 (NBO)。struct timespec の tv_sec 相当。
Definition porter_type.h:218
PotrPacket::session_id
uint32_t session_id
セッション識別子 (NBO)。potrOpenService 時に決定する乱数。
Definition porter_type.h:219
PotrPacket::flags
uint16_t flags
パケット種別フラグ (POTR_FLAG_*) (NBO)。
Definition porter_type.h:223
PotrPacket::payload
const uint8_t * payload
ペイロードデータへのポインタ (読み取り専用)。ウィンドウプールまたは受信バッファ内を指す。
Definition porter_type.h:226
PotrPacket::session_tv_nsec
int32_t session_tv_nsec
セッション開始時刻 ナノ秒部 (NBO)。struct timespec の tv_nsec 相当。
Definition porter_type.h:220
PotrPacket::seq_num
uint32_t seq_num
通番。送信側が付与する連番 (NBO)。
Definition porter_type.h:221
PotrPacket::service_id
int64_t service_id
サービス識別子 (NBO)。受信時に照合する。
Definition porter_type.h:217
PotrPacket::payload_len
uint16_t payload_len
ペイロード長 (バイト) (NBO)。
Definition porter_type.h:224