Document of c-modernization-kit (porter) 1.0.0
Loading...
Searching...
No Matches
send.c
Go to the documentation of this file.
1
40
41#include <inttypes.h>
42#include <signal.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#ifndef _WIN32
48 #include <unistd.h>
49#else /* _WIN32 */
50 #include <windows.h>
51#endif /* _WIN32 */
52
53#include <porter.h>
54#include <console-util.h>
55
57#define INPUT_BUF_SIZE (POTR_MAX_MESSAGE_SIZE + 2U)
58
60static volatile int g_running = 1;
61
62#ifndef _WIN32
69static void sig_handler(int sig)
70{
71 (void)sig;
72 g_running = 0;
73 printf("\n終了中...\n");
74 fflush(stdout);
75 close(STDIN_FILENO); /* fgets のブロックを解除する */
76}
77#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,
123 const void *data, size_t len)
124{
125 char buf[POTR_MAX_PAYLOAD + 1];
126 size_t copy_len;
127
128 (void)peer_id;
129 switch (event)
130 {
132 printf("\n[サービス %" PRId64 "] 接続確立\n", service_id);
133 fflush(stdout);
134 break;
135
137 printf("\n[サービス %" PRId64 "] 切断検知\n", service_id);
138 fflush(stdout);
139 break;
140
141 case POTR_EVENT_DATA:
142 default:
143 if (len < POTR_MAX_PAYLOAD)
144 {
145 copy_len = len;
146 }
147 else
148 {
149 copy_len = POTR_MAX_PAYLOAD;
150 }
151 memcpy(buf, data, copy_len);
152 buf[copy_len] = '\0';
153 printf("\n[サービス %" PRId64 "] 受信 (%zu バイト): %s\n", service_id, len, buf);
154 fflush(stdout);
155 break;
156 }
157}
158
167static int parse_log_level(const char *str, PotrLogLevel *out)
168{
169 static const struct { const char *name; PotrLogLevel level; uint32_t _pad; } tbl[] = {
170 { "DEBUG", POTR_TRACE_VERBOSE, 0U },
171 { "INFO", POTR_TRACE_INFO, 0U },
172 { "WARN", POTR_TRACE_WARNING, 0U },
173 { "ERROR", POTR_TRACE_ERROR, 0U },
174 { "FATAL", POTR_TRACE_CRITICAL, 0U },
175 };
176 char upper[16];
177 size_t i;
178 size_t j;
179
180 for (j = 0; j < sizeof(upper) - 1U && str[j] != '\0'; j++)
181 {
182 upper[j] = (str[j] >= 'a' && str[j] <= 'z')
183 ? (char)(str[j] - ('a' - 'A'))
184 : str[j];
185 }
186 upper[j] = '\0';
187
188 for (i = 0; i < sizeof(tbl) / sizeof(tbl[0]); i++)
189 {
190 if (strcmp(upper, tbl[i].name) == 0)
191 {
192 *out = tbl[i].level;
193 return 1;
194 }
195 }
196 return 0;
197}
198
207static int read_line(char *buf, size_t size)
208{
209 if (fgets(buf, (int)size, stdin) == NULL)
210 {
211 return 0;
212 }
213 buf[strcspn(buf, "\n")] = '\0';
214 return 1;
215}
216
225int main(int argc, char *argv[])
226{
227 const char *config_path;
228 int64_t service_id;
229 PotrHandle handle;
230 char msg_buf[INPUT_BUF_SIZE];
231 char ans_buf[8];
232 size_t msg_len;
233 int compress;
234 int ret = EXIT_SUCCESS;
235 int i;
236 PotrLogLevel log_level = POTR_TRACE_NONE;
237 int log_level_set = 0;
238 PotrType svc_type;
239 int is_bidir;
240 PotrRecvCallback callback;
241
242 /* コンソール UTF-8 ヘルパーを初期化する */
243 console_init();
244
245 /* オプション解析 */
246 for (i = 1; i < argc; i++)
247 {
248 if (strcmp(argv[i], "-l") == 0)
249 {
250 if (i + 1 >= argc)
251 {
252 fprintf(stderr, "エラー: -l オプションにレベルを指定してください。\n");
253 fprintf(stderr, "使用方法: %s [-l <level>] <config_path> <service_id>\n",
254 argv[0]);
255 console_dispose();
256 return EXIT_FAILURE;
257 }
258 i++;
259 if (!parse_log_level(argv[i], &log_level))
260 {
261 fprintf(stderr,
262 "エラー: 不明なログレベル \"%s\"。"
263 "TRACE/DEBUG/INFO/WARN/ERROR/FATAL のいずれかを指定してください。\n",
264 argv[i]);
265 console_dispose();
266 return EXIT_FAILURE;
267 }
268 log_level_set = 1;
269 }
270 else
271 {
272 break; /* 最初の非オプション引数で停止 */
273 }
274 }
275
276 /* positional 引数チェック */
277 if (argc - i < 2)
278 {
279 fprintf(stderr, "使用方法: %s [-l <level>] <config_path> <service_id>\n",
280 argv[0]);
281 fprintf(stderr, " -l <level> ログレベル (TRACE/DEBUG/INFO/WARN/ERROR/FATAL)\n");
282 fprintf(stderr, "例: %s porter-services.conf 10\n", argv[0]);
283 fprintf(stderr, "例: %s -l INFO porter-services.conf 10\n", argv[0]);
284 console_dispose();
285 return EXIT_FAILURE;
286 }
287
288 config_path = argv[i];
289 service_id = (int64_t)strtoll(argv[i + 1], NULL, 10);
290
291 /* ロガー設定 (stderr 出力、ファイルなし) */
292 if (log_level_set)
293 {
294 if (potrLogConfig(log_level, NULL, 1) != POTR_SUCCESS)
295 {
296 fprintf(stderr, "エラー: ロガーの設定に失敗しました。\n");
297 console_dispose();
298 return EXIT_FAILURE;
299 }
300 }
301
302#ifndef _WIN32
303 signal(SIGINT, sig_handler);
304#else /* _WIN32 */
305 SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
306#endif /* _WIN32 */
307
308 printf("サービス %" PRId64 " を開いています... (設定: %s)\n", service_id, config_path);
309 fflush(stdout);
310
311 /* サービス種別を取得して unicast_bidir かどうか判定する */
312 is_bidir = 0;
313 if (potrGetServiceType(config_path, service_id, &svc_type) == POTR_SUCCESS
314 && svc_type == POTR_TYPE_UNICAST_BIDIR)
315 {
316 is_bidir = 1;
317 }
318
319 /* unicast_bidir の場合はコールバックが必須 */
320 callback = is_bidir ? on_recv : NULL;
321
322 if (potrOpenServiceFromConfig(config_path, service_id, POTR_ROLE_SENDER, callback, &handle) != POTR_SUCCESS)
323 {
324 fprintf(stderr, "エラー: サービス %" PRId64 " を開けませんでした。\n", service_id);
325 console_dispose();
326 return EXIT_FAILURE;
327 }
328
329 if (is_bidir)
330 {
331 printf("双方向モード (unicast_bidir)。相手からの受信メッセージも表示します。\n");
332 fflush(stdout);
333 }
334 printf("送信準備完了。空行入力またはCtrl+Dで終了します。\n");
335 fflush(stdout);
336
337 for (;;)
338 {
339 printf("\nメッセージ> ");
340 fflush(stdout);
341
342 if (!read_line(msg_buf, sizeof(msg_buf)))
343 {
344 break;
345 }
346
347 msg_len = strlen(msg_buf);
348 if (msg_len == 0)
349 {
350 break;
351 }
352
353 printf("圧縮送信しますか? [y/N]> ");
354 fflush(stdout);
355
356 compress = 0;
357 if (read_line(ans_buf, sizeof(ans_buf)))
358 {
359 if (ans_buf[0] == 'y' || ans_buf[0] == 'Y')
360 {
361 compress = 1;
362 }
363 }
364
365 const char *compress_label;
366 if (compress)
367 {
368 compress_label = " [圧縮あり]";
369 }
370 else
371 {
372 compress_label = "";
373 }
374 printf("送信中: \"%s\" (%zu バイト)%s\n", msg_buf, msg_len, compress_label);
375 fflush(stdout);
376
377 if (potrSend(handle, POTR_PEER_NA, msg_buf, msg_len,
379 {
380 fprintf(stderr, "エラー: 送信に失敗しました。\n");
381 ret = EXIT_FAILURE;
382 break;
383 }
384
385 printf("送信完了。");
386
387 printf(" 続けて送信しますか? [Y/n]> ");
388 fflush(stdout);
389
390 if (!read_line(ans_buf, sizeof(ans_buf)))
391 {
392 break;
393 }
394
395 if (ans_buf[0] == 'n' || ans_buf[0] == 'N')
396 {
397 break;
398 }
399 }
400
401 potrCloseService(handle);
402 printf("終了しました。\n");
403 fflush(stdout);
404 console_dispose();
405 return ret;
406}
407
#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) と同値。
void(* PotrRecvCallback)(int64_t service_id, PotrPeerId peer_id, PotrEvent event, const void *data, size_t len)
受信コールバック関数型 (全通信種別共通)。
PotrType
通信種別。
Definition porter_type.h:85
@ POTR_TYPE_UNICAST_BIDIR
双方向 1:1 通信 (UDP ユニキャスト)。
Definition porter_type.h:94
struct PotrContext_ * PotrHandle
セッションハンドル。
@ POTR_ROLE_SENDER
送信者。
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 void sig_handler(int sig)
Linux SIGINT シグナルハンドラー。
Definition recv.c:67
static void on_recv(int64_t service_id, PotrPeerId peer_id, PotrEvent event, const void *data, size_t len)
受信コールバック関数。
Definition recv.c:122
static int parse_log_level(const char *str, PotrLogLevel *out)
ログレベル文字列を PotrLogLevel に変換する。
Definition send.c:167
int main(int argc, char *argv[])
メインエントリーポイント。
Definition send.c:225
static int read_line(char *buf, size_t size)
標準入力から1行読み込み、末尾の改行を取り除く。
Definition send.c:207
static void sig_handler(int sig)
Linux SIGINT シグナルハンドラー。
Definition send.c:69
static void on_recv(int64_t service_id, PotrPeerId peer_id, PotrEvent event, const void *data, size_t len)
受信コールバック関数 (unicast_bidir モード用)。
Definition send.c:122
#define INPUT_BUF_SIZE
入力バッファサイズ。POTR_MAX_MESSAGE_SIZE + 改行 + NUL。
Definition send.c:57