Document of c-modernization-kit (porter) 1.0.0
Loading...
Searching...
No Matches
recv.c
Go to the documentation of this file.
1
39
40#include <inttypes.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46#ifndef _WIN32
47 #include <pthread.h>
48 #include <unistd.h>
49#else /* _WIN32 */
50 #include <process.h>
51 #include <windows.h>
52#endif /* _WIN32 */
53
54#include <porter.h>
55#include <console-util.h>
56
58static volatile int g_running = 1;
59
60#ifndef _WIN32
67static void sig_handler(int sig)
68{
69 (void)sig;
70 g_running = 0;
71 printf("\n終了中...\n");
72 fflush(stdout);
73}
74#else /* _WIN32 */
94static BOOL WINAPI console_ctrl_handler(DWORD type)
95{
96 switch (type)
97 {
98 case CTRL_C_EVENT:
99 case CTRL_BREAK_EVENT:
100 case CTRL_CLOSE_EVENT:
101 case CTRL_SHUTDOWN_EVENT:
102 g_running = 0;
103 printf("\n終了中...\n");
104 fflush(stdout);
105 return TRUE;
106 }
107
108 return FALSE;
109}
110#endif /* _WIN32 */
111
122static void on_recv(int64_t service_id, PotrPeerId peer_id, PotrEvent event, const void *data, size_t len)
123{
124 char buf[POTR_MAX_PAYLOAD + 1];
125 size_t copy_len;
126
127 (void)peer_id;
128 switch (event)
129 {
131 printf("[サービス %" PRId64 "] 接続確立\n", service_id);
132 fflush(stdout);
133 break;
134
136 printf("[サービス %" PRId64 "] 切断検知\n", service_id);
137 fflush(stdout);
138 break;
139
140 case POTR_EVENT_DATA:
141 default:
142 if (len < POTR_MAX_PAYLOAD)
143 {
144 copy_len = len;
145 }
146 else
147 {
148 copy_len = POTR_MAX_PAYLOAD;
149 }
150 memcpy(buf, data, copy_len);
151 buf[copy_len] = '\0';
152 printf("[サービス %" PRId64 "] 受信 (%zu バイト): %s\n", service_id, len, buf);
153 fflush(stdout);
154 break;
155 }
156}
157
166static int parse_log_level(const char *str, PotrLogLevel *out)
167{
168 static const struct
169 {
170 const char *name;
171 PotrLogLevel level;
172 uint32_t _pad;
173 } tbl[] = {
174 {"DEBUG", POTR_TRACE_VERBOSE, 0U}, {"INFO", POTR_TRACE_INFO, 0U},
175 {"WARN", POTR_TRACE_WARNING, 0U}, {"ERROR", POTR_TRACE_ERROR, 0U}, {"FATAL", POTR_TRACE_CRITICAL, 0U},
176 };
177 char upper[16];
178 size_t i;
179 size_t j;
180
181 for (j = 0; j < sizeof(upper) - 1U && str[j] != '\0'; j++)
182 {
183 upper[j] = (str[j] >= 'a' && str[j] <= 'z') ? (char)(str[j] - ('a' - 'A')) : str[j];
184 }
185 upper[j] = '\0';
186
187 for (i = 0; i < sizeof(tbl) / sizeof(tbl[0]); i++)
188 {
189 if (strcmp(upper, tbl[i].name) == 0)
190 {
191 *out = tbl[i].level;
192 return 1;
193 }
194 }
195 return 0;
196}
197
198/* ============================================================ */
199/* unicast_bidir 送信スレッド */
200/* ============================================================ */
201
203typedef struct
204{
206 volatile int *running;
208
217static int read_line(char *buf, size_t size)
218{
219 if (fgets(buf, (int)size, stdin) == NULL)
220 {
221 return 0;
222 }
223 buf[strcspn(buf, "\n")] = '\0';
224 return 1;
225}
226
227#ifndef _WIN32
228typedef pthread_t BidirThread;
229
237static void *bidir_send_thread_func(void *arg)
238#else /* _WIN32 */
239typedef HANDLE BidirThread;
240
248static unsigned __stdcall bidir_send_thread_func(void *arg)
249#endif /* _WIN32 */
250{
251 BidirSendCtx *ctx = (BidirSendCtx *)arg;
252 char msg_buf[POTR_MAX_MESSAGE_SIZE + 2U];
253 char ans_buf[8];
254 size_t msg_len;
255 int compress;
256 const char *compress_label;
257
258 while (*ctx->running)
259 {
260 printf("\nメッセージ> ");
261 fflush(stdout);
262
263 if (!read_line(msg_buf, sizeof(msg_buf)))
264 {
265 break; /* EOF またはシグナル割り込み */
266 }
267
268 msg_len = strlen(msg_buf);
269 if (msg_len == 0U)
270 {
271 break; /* 空行で送信終了 */
272 }
273
274 printf("圧縮送信しますか? [y/N]> ");
275 fflush(stdout);
276
277 compress = 0;
278 if (read_line(ans_buf, sizeof(ans_buf)))
279 {
280 if (ans_buf[0] == 'y' || ans_buf[0] == 'Y')
281 {
282 compress = 1;
283 }
284 }
285
286 compress_label = compress ? " [圧縮あり]" : "";
287 printf("送信中: \"%s\" (%zu バイト)%s\n", msg_buf, msg_len, compress_label);
288
289 if (potrSend(ctx->handle, POTR_PEER_NA, msg_buf, msg_len,
291 {
292 fprintf(stderr, "エラー: 送信に失敗しました。\n");
293 break;
294 }
295
296 printf("送信完了。");
297
298 printf(" 続けて送信しますか? [Y/n]> ");
299 fflush(stdout);
300
301 if (!read_line(ans_buf, sizeof(ans_buf)))
302 {
303 break;
304 }
305
306 if (ans_buf[0] == 'n' || ans_buf[0] == 'N')
307 {
308 break;
309 }
310 }
311
312 *ctx->running = 0; /* 送信終了時に受信ループも停止させる */
313
314#ifndef _WIN32
315 return NULL;
316#else /* _WIN32 */
317 return 0U;
318#endif /* _WIN32 */
319}
320
330{
331#ifndef _WIN32
332 return pthread_create(thread, NULL, bidir_send_thread_func, ctx) == 0;
333#else /* _WIN32 */
334 uintptr_t h = _beginthreadex(NULL, 0U, bidir_send_thread_func, ctx, 0U, NULL);
335 if (h == 0U)
336 {
337 return 0;
338 }
339 *thread = (HANDLE)h;
340 return 1;
341#endif /* _WIN32 */
342}
343
351{
352#ifndef _WIN32
353 pthread_cancel(thread); /* fgets でブロック中のスレッドを中断する */
354 pthread_join(thread, NULL);
355#else /* _WIN32 */
356 WaitForSingleObject(thread, INFINITE);
357 CloseHandle(thread);
358#endif /* _WIN32 */
359}
360
369int main(int argc, char *argv[])
370{
371 const char *config_path;
372 int64_t service_id;
373 PotrHandle handle;
374 int i;
375 PotrLogLevel log_level = POTR_TRACE_NONE;
376 int log_level_set = 0;
377 PotrType svc_type;
378 int is_bidir;
379 BidirSendCtx bidir_ctx;
380 BidirThread bidir_thread = 0;
381 int bidir_started = 0;
382
383 /* コンソール UTF-8 ヘルパーを初期化する */
384 console_init();
385
386 /* オプション解析 */
387 for (i = 1; i < argc; i++)
388 {
389 if (strcmp(argv[i], "-l") == 0)
390 {
391 if (i + 1 >= argc)
392 {
393 fprintf(stderr, "エラー: -l オプションにレベルを指定してください。\n");
394 fprintf(stderr, "使用方法: %s [-l <level>] <config_path> <service_id>\n", argv[0]);
395 console_dispose();
396 return EXIT_FAILURE;
397 }
398 i++;
399 if (!parse_log_level(argv[i], &log_level))
400 {
401 fprintf(stderr,
402 "エラー: 不明なログレベル \"%s\"。"
403 "TRACE/DEBUG/INFO/WARN/ERROR/FATAL のいずれかを指定してください。\n",
404 argv[i]);
405 console_dispose();
406 return EXIT_FAILURE;
407 }
408 log_level_set = 1;
409 }
410 else
411 {
412 break; /* 最初の非オプション引数で停止 */
413 }
414 }
415
416 /* positional 引数チェック */
417 if (argc - i < 2)
418 {
419 fprintf(stderr, "使用方法: %s [-l <level>] <config_path> <service_id>\n", argv[0]);
420 fprintf(stderr, " -l <level> ログレベル (TRACE/DEBUG/INFO/WARN/ERROR/FATAL)\n");
421 fprintf(stderr, "例: %s porter-services.conf 10\n", argv[0]);
422 fprintf(stderr, "例: %s -l INFO porter-services.conf 10\n", argv[0]);
423 console_dispose();
424 return EXIT_FAILURE;
425 }
426
427 config_path = argv[i];
428 service_id = (int64_t)strtoll(argv[i + 1], NULL, 10);
429
430 /* ロガー設定 (stderr 出力、ファイルなし) */
431 if (log_level_set)
432 {
433 if (potrLogConfig(log_level, NULL, 1) != POTR_SUCCESS)
434 {
435 fprintf(stderr, "エラー: ロガーの設定に失敗しました。\n");
436 console_dispose();
437 return EXIT_FAILURE;
438 }
439 }
440
441#ifndef _WIN32
442 signal(SIGINT, sig_handler);
443#else /* _WIN32 */
444 SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
445#endif /* _WIN32 */
446
447 printf("サービス %" PRId64 " を開いています... (設定: %s)\n", service_id, config_path);
448 fflush(stdout);
449
450 /* サービス種別を取得して unicast_bidir かどうか判定する */
451 is_bidir = 0;
452 if (potrGetServiceType(config_path, service_id, &svc_type) == POTR_SUCCESS && svc_type == POTR_TYPE_UNICAST_BIDIR)
453 {
454 is_bidir = 1;
455 }
456
457 if (potrOpenServiceFromConfig(config_path, service_id, POTR_ROLE_RECEIVER, on_recv, &handle) != POTR_SUCCESS)
458 {
459 fprintf(stderr, "エラー: サービス %" PRId64 " を開けませんでした。\n", service_id);
460 console_dispose();
461 return EXIT_FAILURE;
462 }
463
464 if (is_bidir)
465 {
466 printf("双方向モード (unicast_bidir)。\n");
467 printf("メッセージを入力して送信できます (空行または Ctrl+D で送信終了)。\n");
468 fflush(stdout);
469 bidir_ctx.handle = handle;
470 bidir_ctx.running = &g_running;
471 if (start_bidir_send_thread(&bidir_thread, &bidir_ctx))
472 {
473 bidir_started = 1;
474 }
475 else
476 {
477 fprintf(stderr, "警告: 送信スレッドの起動に失敗しました。受信専用モードで動作します。\n");
478 }
479 }
480
481 printf("受信待機中... (Ctrl+C で終了)\n");
482 fflush(stdout);
483
484 while (g_running)
485 {
486#ifndef _WIN32
487 usleep(100000);
488#else /* _WIN32 */
489 Sleep(100);
490#endif /* _WIN32 */
491 }
492
493 if (bidir_started)
494 {
495 join_bidir_send_thread(bidir_thread);
496 }
497
498 potrCloseService(handle);
499 printf("終了しました。\n");
500 fflush(stdout);
501 console_dispose();
502 return EXIT_SUCCESS;
503}
#define POTR_MAX_MESSAGE_SIZE
1 回の potrSend で送信できる最大メッセージ長 (バイト) のデフォルト値。設定ファイルの max_message_size で変更可能。フラグメント化により max_payload を超える...
#define POTR_MAX_PAYLOAD
ペイロードの最大長 (バイト)。UDP 最大ペイロード (65535 - IP20 - UDP8)。max_payload 設定値のバリデーション上限として使用する。
#define POTR_PEER_NA
ピア ID 未割当を示す予約値。 1:1 モードのコールバックで渡される (ピアの概念がない)。 potrSend() に N:1 モードで指定した場合はエラーを返す。
#define POTR_SUCCESS
成功の戻り値を表す定数。
#define POTR_SEND_COMPRESS
メッセージを圧縮して送信します。圧縮後のサイズが元のサイズ以上の場合は自動的に非圧縮で送信します。
#define POTR_SEND_BLOCKING
ブロッキング送信を行います。0 を指定するとノンブロッキング送信を行います。
通信ライブラリ (動的リンク用) のヘッダーファイル。
POTR_EXPORT int POTR_API potrGetServiceType(const char *config_path, int64_t service_id, PotrType *type)
設定ファイルから指定サービスの通信種別を取得します。
POTR_EXPORT int POTR_API potrLogConfig(PotrLogLevel level, const char *log_file, int console)
ロガーを設定します。
Definition potrLog.c:72
POTR_EXPORT int POTR_API potrSend(PotrHandle handle, PotrPeerId peer_id, const void *data, size_t len, int flags)
メッセージを送信します。
Definition potrSend.c:88
POTR_EXPORT int POTR_API potrOpenServiceFromConfig(const char *config_path, int64_t service_id, PotrRole role, PotrRecvCallback callback, PotrHandle *handle)
設定ファイルから指定サービスを開きます。
POTR_EXPORT int POTR_API potrCloseService(PotrHandle handle)
サービスを閉じます。
PotrLogLevel
ログレベル。
@ POTR_TRACE_ERROR
エラー。操作の失敗を記録。TRACE_LV_ERROR (1) と同値。
@ POTR_TRACE_NONE
ログ出力無効。TRACE_LV_NONE (5) と同値。
@ POTR_TRACE_INFO
情報。TRACE_LV_INFO (3) と同値。
@ POTR_TRACE_VERBOSE
詳細情報 (デバッグ)。TRACE_LV_VERBOSE (4) と同値。
@ POTR_TRACE_CRITICAL
致命的エラー。回復不能な障害を記録。TRACE_LV_CRITICAL (0) と同値。
@ POTR_TRACE_WARNING
警告。回復可能な異常を記録。TRACE_LV_WARNING (2) と同値。
PotrType
通信種別。
Definition porter_type.h:85
@ POTR_TYPE_UNICAST_BIDIR
双方向 1:1 通信 (UDP ユニキャスト)。
Definition porter_type.h:94
struct PotrContext_ * PotrHandle
セッションハンドル。
@ POTR_ROLE_RECEIVER
受信者。
uint32_t PotrPeerId
ピア識別子。
Definition porter_type.h:32
PotrEvent
受信イベント種別。
@ POTR_EVENT_DISCONNECTED
切断を検知 (タイムアウト / FIN 受信 / REJECT 受信)。data=NULL, len=0。
@ POTR_EVENT_CONNECTED
送信者からの疎通を初検知 or 復帰。data=NULL, len=0。
@ POTR_EVENT_DATA
データ受信。data/len に内容が格納される。
static volatile int g_running
受信ループ継続フラグ。シグナルハンドラーで 0 に設定される。
Definition recv.c:58
static int parse_log_level(const char *str, PotrLogLevel *out)
ログレベル文字列を PotrLogLevel に変換する。
Definition recv.c:166
int main(int argc, char *argv[])
メインエントリーポイント。
Definition recv.c:369
static int read_line(char *buf, size_t size)
標準入力から1行読み込み、末尾の改行を取り除く。
Definition recv.c:217
static void sig_handler(int sig)
Linux SIGINT シグナルハンドラー。
Definition recv.c:67
static void * bidir_send_thread_func(void *arg)
bidir 送信スレッド関数 (Linux)。
Definition recv.c:237
static void join_bidir_send_thread(BidirThread thread)
bidir 送信スレッドの終了を待機して破棄する。
Definition recv.c:350
static void on_recv(int64_t service_id, PotrPeerId peer_id, PotrEvent event, const void *data, size_t len)
受信コールバック関数。
Definition recv.c:122
pthread_t BidirThread
Definition recv.c:228
static int start_bidir_send_thread(BidirThread *thread, BidirSendCtx *ctx)
bidir 送信スレッドを起動する。
Definition recv.c:329
bidir 送信スレッドに渡すコンテキスト。
Definition recv.c:204
volatile int * running
Definition recv.c:206
PotrHandle handle
Definition recv.c:205