Document of c-modernization-kit (porter) 1.0.0
Loading...
Searching...
No Matches
potrCloseService.c
Go to the documentation of this file.
1
13
14#include <stdlib.h>
15#include <string.h>
16#include <inttypes.h>
17
18#ifndef _WIN32
19 #include <arpa/inet.h>
20 #include <netinet/in.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23#else /* _WIN32 */
24 #include <winsock2.h>
25 #include <ws2tcpip.h>
26#endif /* _WIN32 */
27
28#include <porter_const.h>
29#include <porter.h>
30
31#include "../potrContext.h"
32#include "../potrPeerTable.h"
38#include "../protocol/packet.h"
39#include "../protocol/window.h"
40#include "../util/potrIpAddr.h"
41#include "../infra/potrLog.h"
43
44/* FIN パケットを全パスへ送信する */
45static void send_fin(struct PotrContext_ *ctx)
46{
47 PotrPacket fin_pkt;
49 size_t wire_len;
50 int i;
51
52 shdr.service_id = ctx->service.service_id;
53 shdr.session_id = ctx->session_id;
56
57 if (packet_build_fin(&fin_pkt, &shdr) != POTR_SUCCESS) return;
58
59 if (ctx->service.encrypt_enabled)
60 {
61 uint8_t wire_buf[PACKET_HEADER_SIZE + POTR_CRYPTO_TAG_SIZE];
62 uint8_t nonce[POTR_CRYPTO_NONCE_SIZE];
63 size_t enc_out = POTR_CRYPTO_TAG_SIZE;
64
65 fin_pkt.flags |= htons(POTR_FLAG_ENCRYPTED);
66 fin_pkt.payload_len = htons((uint16_t)POTR_CRYPTO_TAG_SIZE);
67
68 /* ノンス: session_id(4B) + flags(2B, FIN|ENCRYPTED NBO) + 0(4B) + padding(2B) */
69 memcpy(nonce, &fin_pkt.session_id, 4);
70 memcpy(nonce + 4, &fin_pkt.flags, 2);
71 memset(nonce + 6, 0, 4);
72 memset(nonce + 10, 0, 2);
73
74 memcpy(wire_buf, &fin_pkt, PACKET_HEADER_SIZE);
75 if (potr_encrypt(wire_buf + PACKET_HEADER_SIZE, &enc_out,
76 NULL, 0,
78 nonce,
79 wire_buf, PACKET_HEADER_SIZE) != 0)
80 {
81 return;
82 }
83 wire_len = PACKET_HEADER_SIZE + enc_out;
84
85 for (i = 0; i < ctx->n_path; i++)
86 {
87 if (ctx->sock[i] == POTR_INVALID_SOCKET) continue;
88#ifndef _WIN32
89 sendto(ctx->sock[i], wire_buf, wire_len, 0,
90 (const struct sockaddr *)&ctx->dest_addr[i],
91 sizeof(ctx->dest_addr[i]));
92#else /* _WIN32 */
93 sendto(ctx->sock[i], (const char *)wire_buf, (int)wire_len, 0,
94 (const struct sockaddr *)&ctx->dest_addr[i],
95 sizeof(ctx->dest_addr[i]));
96#endif /* _WIN32 */
97 }
98 }
99 else
100 {
101 wire_len = packet_wire_size(&fin_pkt);
102
103 for (i = 0; i < ctx->n_path; i++)
104 {
105 if (ctx->sock[i] == POTR_INVALID_SOCKET) continue;
106#ifndef _WIN32
107 sendto(ctx->sock[i], &fin_pkt, wire_len, 0,
108 (const struct sockaddr *)&ctx->dest_addr[i],
109 sizeof(ctx->dest_addr[i]));
110#else /* _WIN32 */
111 sendto(ctx->sock[i], (const char *)&fin_pkt, (int)wire_len, 0,
112 (const struct sockaddr *)&ctx->dest_addr[i],
113 sizeof(ctx->dest_addr[i]));
114#endif /* _WIN32 */
115 }
116 }
117}
118
119/* doxygen コメントは、ヘッダに記載 */
121{
122 struct PotrContext_ *ctx = (struct PotrContext_ *)handle;
123
124 if (ctx == NULL)
125 {
126 POTR_LOG(POTR_TRACE_ERROR, "potrCloseService: handle is NULL");
127 return POTR_ERROR;
128 }
129
131 "potrCloseService: service_id=%" PRId64 " closing",
132 ctx->service.service_id);
133
134 /* TCP: 接続管理スレッドを停止する (send/recv/health スレッドは connect スレッド内で停止) */
135 if (potr_is_tcp_type(ctx->service.type))
136 {
138 "potrCloseService: service_id=%" PRId64 " stopping connect thread (TCP)",
139 ctx->service.service_id);
141
142 /* 送信キューを破棄 (SENDER / TCP_BIDIR のみ) */
143 if (ctx->role == POTR_ROLE_SENDER
145 {
147 }
148
149 /* TCP mutex / condvar を解放 */
150#ifndef _WIN32
151 {
152 int i;
153 pthread_mutex_destroy(&ctx->tcp_state_mutex);
154 pthread_cond_destroy(&ctx->tcp_state_cv);
155 for (i = 0; i < (int)POTR_MAX_PATH; i++)
156 {
157 pthread_mutex_destroy(&ctx->tcp_send_mutex[i]);
158 pthread_mutex_destroy(&ctx->health_mutex[i]);
159 pthread_cond_destroy(&ctx->health_wakeup[i]);
160 }
161 pthread_mutex_destroy(&ctx->recv_window_mutex);
162 }
163#else /* _WIN32 */
164 {
165 int i;
166 DeleteCriticalSection(&ctx->tcp_state_mutex);
167 /* Windows の CONDITION_VARIABLE は破棄不要 */
168 for (i = 0; i < (int)POTR_MAX_PATH; i++)
169 {
170 DeleteCriticalSection(&ctx->tcp_send_mutex[i]);
171 DeleteCriticalSection(&ctx->health_mutex[i]);
172 }
173 DeleteCriticalSection(&ctx->recv_window_mutex);
174 }
175#endif /* _WIN32 */
176
177 /* 送受信ウィンドウと動的バッファを解放 */
180 free(ctx->frag_buf);
181 free(ctx->compress_buf);
182 free(ctx->crypto_buf);
183 free(ctx->recv_buf);
184 free(ctx->send_wire_buf);
185
186#ifdef _WIN32
187 WSACleanup();
188#endif /* _WIN32 */
189
191 "potrCloseService: service closed (TCP)");
192 free(ctx);
193 return POTR_SUCCESS;
194 }
195
196 /* 非 TCP: ヘルスチェックスレッドを停止 (送信者のみ) */
197 if (ctx->health_running)
198 {
200 "potrCloseService: service_id=%" PRId64 " stopping health thread",
201 ctx->service.service_id);
203 }
204
205 /* 送信スレッドを停止してキューを破棄 (送信者のみ) */
206 if (ctx->send_thread_running)
207 {
209 "potrCloseService: service_id=%" PRId64 " flushing send queue and sending FIN",
210 ctx->service.service_id);
212 if (ctx->is_multi_peer)
213 {
214 /* N:1: 全アクティブピアへ FIN を送信してピアテーブルを破棄 */
216 }
217 else
218 {
219 /* 1:1: 単一宛先へ FIN を送信 */
220 send_fin(ctx);
221 }
224 }
225
226 /* 受信スレッドを停止する */
227 if (ctx->running)
228 {
230 "potrCloseService: service_id=%" PRId64 " stopping recv thread",
231 ctx->service.service_id);
233 }
234
235 /* ソケットをクローズ (recv スレッドの有無によらず実施)。
236 Windows: comm_recv_thread_stop 内で closesocket 済みの場合は INVALID_SOCKET になっているため
237 guard により二重 close を回避する。
238 Linux: comm_recv_thread_stop は shutdown のみで close しないため、ここで必ず close する。 */
239 {
240 int i;
241 for (i = 0; i < ctx->n_path; i++)
242 {
243 if (ctx->sock[i] == POTR_INVALID_SOCKET) continue;
244#ifndef _WIN32
246 {
247 struct ip_mreq mreq;
248 memset(&mreq, 0, sizeof(mreq));
249 if (parse_ipv4_addr(ctx->service.multicast_group, &mreq.imr_multiaddr)
250 == POTR_SUCCESS)
251 {
252 mreq.imr_interface = ctx->src_addr_resolved[i];
253 setsockopt(ctx->sock[i], IPPROTO_IP, IP_DROP_MEMBERSHIP,
254 &mreq, sizeof(mreq));
255 }
256 }
257 close(ctx->sock[i]);
258#else /* _WIN32 */
260 {
261 struct ip_mreq mreq;
262 memset(&mreq, 0, sizeof(mreq));
263 if (parse_ipv4_addr(ctx->service.multicast_group, &mreq.imr_multiaddr)
264 == POTR_SUCCESS)
265 {
266 mreq.imr_interface = ctx->src_addr_resolved[i];
267 setsockopt(ctx->sock[i], IPPROTO_IP, IP_DROP_MEMBERSHIP,
268 (const char *)&mreq, sizeof(mreq));
269 }
270 }
271 closesocket(ctx->sock[i]);
272#endif /* _WIN32 */
273 ctx->sock[i] = POTR_INVALID_SOCKET;
274 }
275 }
276
277#ifdef _WIN32
278 WSACleanup();
279#endif /* _WIN32 */
280
281 /* 送受信ウィンドウと動的バッファを解放 */
282 if (!ctx->is_multi_peer)
283 {
284 /* 1:1 モード: コンテキストレベルのウィンドウを解放する */
287 }
288 else if (ctx->peers != NULL)
289 {
290 /* N:1 モード: 送信スレッド未起動の場合もピアテーブルを解放する
291 (既に peer_table_destroy 済みの場合は ctx->peers が NULL になっている) */
293 }
294 free(ctx->frag_buf);
295 free(ctx->compress_buf);
296 free(ctx->crypto_buf);
297 free(ctx->recv_buf);
298 free(ctx->send_wire_buf);
299
301 "potrCloseService: service closed");
302
303 free(ctx);
304 return POTR_SUCCESS;
305}
データ暗号化・復号モジュールの内部ヘッダー。
int potr_encrypt(uint8_t *dst, size_t *dst_len, const uint8_t *src, size_t src_len, const uint8_t *key, const uint8_t *nonce, const uint8_t *aad, size_t aad_len)
AES-256-GCM でデータを暗号化します。
#define POTR_CRYPTO_NONCE_SIZE
AES-256-GCM ノンスサイズ (バイト)。session_id (4B NBO) + flags (2B NBO) + seq_or_ack_num (4B NBO) + padding (2B...
#define POTR_CRYPTO_TAG_SIZE
AES-256-GCM 認証タグサイズ (バイト)。暗号文の直後に付加する。
#define POTR_MAX_PATH
マルチパスの最大パス数。
#define POTR_FLAG_ENCRYPTED
AES-256-GCM 認証タグが付与されていることを示す外側パケットフラグ。 POTR_FLAG_DATA と組み合わせる場合: [ヘッダー 32B][暗号文: packed_len B][GCM ...
#define POTR_SUCCESS
成功の戻り値を表す定数。
#define POTR_ERROR
失敗の戻り値を表す定数。
int packet_build_fin(PotrPacket *packet, const PotrPacketSessionHdr *shdr)
正常終了通知 (FIN) パケットを構築します。
Definition packet.c:163
size_t packet_wire_size(const PotrPacket *packet)
パケットのヘッダー + ペイロードの合計バイト数を返します。
Definition packet.c:347
パケット構築・解析モジュールの内部ヘッダー。
#define PACKET_HEADER_SIZE
パケットヘッダーの固定長 (バイト)。payload フィールドの開始オフセット。
Definition packet.h:23
通信ライブラリ (動的リンク用) のヘッダーファイル。
#define POTR_API
呼び出し規約マクロ。
Definition porter.h:46
#define POTR_EXPORT
DLL エクスポート/インポート制御マクロ。
Definition porter.h:37
通信ライブラリの定数ファイル。
@ POTR_TRACE_ERROR
エラー。操作の失敗を記録。TRACE_LV_ERROR (1) と同値。
@ POTR_TRACE_INFO
情報。TRACE_LV_INFO (3) と同値。
@ POTR_TRACE_VERBOSE
詳細情報 (デバッグ)。TRACE_LV_VERBOSE (4) と同値。
@ POTR_TYPE_TCP_BIDIR
TCP 双方向通信 (両端が potrSend 可)。
@ POTR_TYPE_MULTICAST
1:N 通信 (UDP マルチキャスト)。
Definition porter_type.h:91
struct PotrContext_ * PotrHandle
セッションハンドル。
@ POTR_ROLE_SENDER
送信者。
static void send_fin(struct PotrContext_ *ctx)
POTR_EXPORT int POTR_API potrCloseService(PotrHandle handle)
サービスを閉じます。
void potr_connect_thread_stop(struct PotrContext_ *ctx)
TCP 接続管理スレッドを停止します。
TCP 接続管理スレッドの内部ヘッダー。
セッションコンテキスト内部定義ヘッダー。
#define POTR_INVALID_SOCKET
Definition potrContext.h:36
static PotrType potr_raw_base_type(PotrType t)
RAW 系通信種別をベース通信種別に変換する (非 RAW 型はそのまま返す)。
Definition potrContext.h:62
static int potr_is_tcp_type(PotrType t)
TCP 通信種別 (POTR_TYPE_TCP / POTR_TYPE_TCP_BIDIR) か判定する。
Definition potrContext.h:48
int potr_health_thread_stop(struct PotrContext_ *ctx)
非 TCP ヘルスチェックスレッドを停止します。
ヘルスチェックスレッド内部ヘッダー。
int parse_ipv4_addr(const char *ip_str, struct in_addr *out_addr)
Definition potrIpAddr.c:28
IPv4 アドレス変換ユーティリティ (内部用)。
porter 内部ログマクロ定義ヘッダー。
#define POTR_LOG(level,...)
porter 内部ログ出力マクロ。
Definition potrLog.h:68
void peer_table_destroy(struct PotrContext_ *ctx)
ピアテーブルを破棄する。
N:1 モード用ピアテーブル管理モジュールの内部ヘッダー。
int comm_recv_thread_stop(struct PotrContext_ *ctx)
非 TCP 受信スレッドを停止します。
受信スレッド内部ヘッダー。
void potr_send_queue_destroy(PotrSendQueue *q)
void potr_send_queue_wait_drained(PotrSendQueue *q)
非同期送信キューの型定義と操作関数。
void potr_send_thread_stop(struct PotrContext_ *ctx)
非同期送信スレッドの内部ヘッダー。
セッションコンテキスト構造体。PotrHandle の実体。
uint32_t session_id
自セッション識別子 (乱数)。
uint8_t * frag_buf
フラグメント結合バッファ (動的確保。max_message_size バイト)。
PotrCondVar health_wakeup[POTR_MAX_PATH]
ヘルスチェックスレッドを即時起床させる条件変数 (path ごと)。
struct in_addr src_addr_resolved[POTR_MAX_PATH]
解決済み送信元 IPv4 アドレス。
int32_t session_tv_nsec
自セッション開始時刻 ナノ秒部。
PotrRole role
役割 (POTR_ROLE_SENDER / POTR_ROLE_RECEIVER)。
uint8_t * crypto_buf
暗号化・復号用一時バッファ (動的確保)。
PotrSendQueue send_queue
非同期送信キュー。
uint8_t * compress_buf
圧縮・解凍用一時バッファ (動的確保)。
uint8_t * recv_buf
受信バッファ / 再送 wire 組立バッファ (動的確保。PACKET_HEADER_SIZE + max_payload バイト)。
uint8_t * send_wire_buf
送信 wire 組立バッファ (動的確保。PACKET_HEADER_SIZE + max_payload バイト)。送信スレッドのみ使用。
volatile int running[POTR_MAX_PATH]
受信スレッド実行フラグ (1: 実行中, 0: 停止)。path ごと。
PotrMutex tcp_send_mutex[POTR_MAX_PATH]
TCP send() 排他制御 (path ごと)。送信スレッド・ヘルスチェックスレッド・recv スレッド競合防止。
PotrMutex tcp_state_mutex
tcp_state_cv 保護用ミューテックス。tcp_active_paths のカウンタ更新も保護。
int is_multi_peer
1: N:1 モード (src_addr/src_port 省略), 0: 1:1 モード。
PotrServiceDef service
サービス定義。
PotrMutex health_mutex[POTR_MAX_PATH]
ヘルスチェックスレッド停止用ミューテックス (path ごと)。
PotrSocket sock[POTR_MAX_PATH]
各パスの UDP ソケット。
volatile int health_running[POTR_MAX_PATH]
ヘルスチェックスレッド実行フラグ (1: 実行中, 0: 停止)。path ごと。
PotrWindow send_window
送信バッファ (過去 N パケット保持。NACK 再送・REJECT 判定に使用)。
volatile int send_thread_running
送信スレッド実行フラグ (1: 実行中, 0: 停止)。
PotrCondVar tcp_state_cv
切断通知・reconnect sleep の中断用条件変数。
PotrMutex recv_window_mutex
recv_window 保護用ミューテックス。
struct sockaddr_in dest_addr[POTR_MAX_PATH]
送信先ソケットアドレス (送信者が sendto に使用)。
PotrWindow recv_window
受信ウィンドウ (順序整列・欠番検出)。
int64_t session_tv_sec
自セッション開始時刻 秒部。
int n_path
有効パス数。
PotrPeerContext * peers
ピアテーブル (動的確保。max_peers エントリ)。
パケットに付与するセッション識別情報。
Definition packet.h:31
int32_t session_tv_nsec
セッション開始時刻 ナノ秒部。
Definition packet.h:35
int64_t service_id
サービス識別子。
Definition packet.h:32
uint32_t session_id
セッション識別子 (乱数)。
Definition packet.h:34
int64_t session_tv_sec
セッション開始時刻 秒部。
Definition packet.h:33
ネットワーク送受信用パケット構造体。
uint32_t session_id
セッション識別子 (NBO)。potrOpenService 時に決定する乱数。
uint16_t flags
パケット種別フラグ (POTR_FLAG_*) (NBO)。
uint16_t payload_len
ペイロード長 (バイト) (NBO)。
int encrypt_enabled
非 0 のとき暗号化有効。設定ファイルに有効な encrypt_key が存在するときに 1 に設定される。
char multicast_group[POTR_MAX_ADDR_LEN]
マルチキャストグループアドレス。(multicast のみ)
PotrType type
通信種別。
int64_t service_id
サービス ID。
uint8_t encrypt_key[POTR_CRYPTO_KEY_SIZE]
AES-256-GCM 事前共有鍵 (32 バイト)。encrypt_enabled が 0 の場合は未使用。
void window_destroy(PotrWindow *win)
ウィンドウが保持する動的確保バッファを解放します。
Definition window.c:110
スライディングウィンドウ管理モジュールの内部ヘッダー。