# porter/include/porter.h

# 1 ファイル

## 1.1 porter/include/porter.h

通信ライブラリ (動的リンク用) のヘッダーファイル。

このライブラリは UDP/IP を用いたプラットフォーム間通信を提供します。
Linux / Windows クロスプラットフォーム対応の DLL として提供されます。

### 1.1.1 作者

c-modernization-kit sample team

### 1.1.2 バージョン

1.0.0

### 1.1.3 日付

2026/03/04

### 1.1.4 著作権

Copyright (C) CompanyName, Ltd. 2026. All rights reserved.

# 2 関数

## 2.1 potrOpenService

    POTR_EXPORT int POTR_API potrOpenService ( const PotrGlobalConfig *global, const PotrServiceDef *service, PotrRole role, PotrRecvCallback callback, PotrHandle *handle )

設定構造体から指定サービスを開きます。

設定構造体からサービス定義を取得し、UDP ソケットを初期化します。
role と callback の組み合わせが不正な場合は POTR_ERROR を返します。
role と設定の IP アドレスが不整合 (bind 失敗など) の場合も POTR_ERROR を返します。
通信種別・役割に応じて以下のソケット設定を行います。

通信種別 | 役割 | bind アドレス | bind ポート
--- | --- | --- | ---
POTR_TYPE_UNICAST | 送信者 | src_addr | src_port
POTR_TYPE_UNICAST | 受信者 | dst_addr | dst_port
POTR_TYPE_MULTICAST | 送信者 | INADDR_ANY | src_port
POTR_TYPE_MULTICAST | 受信者 | INADDR_ANY | dst_port
POTR_TYPE_BROADCAST | 送信者 | src_addr | src_port
POTR_TYPE_BROADCAST | 受信者 | INADDR_ANY | dst_port

POTR_ROLE_RECEIVER の場合、内部で受信スレッドを起動します。

### 2.1.1 引数

- global [in] グローバル設定構造体へのポインタ。
- service [in] サービス定義構造体へのポインタ。
- role [in] 役割種別。POTR_ROLE_SENDER または POTR_ROLE_RECEIVER。
- callback [in] イベント発生時に呼び出されるコールバック関数 (PotrRecvCallback)。 POTR_ROLE_RECEIVER の場合は必須。データ受信・接続検知・切断検知を受け取る。 POTR_ROLE_SENDER の場合は通常 NULL を指定すること。
  ただし POTR_TYPE_TCP_BIDIR および POTR_TYPE_UNICAST_BIDIR では SENDER にもコールバックが必須。これらの種別では POTR_ROLE_SENDER でも callback が NULL の場合は失敗を返します。
- handle [out] 成功時にセッションハンドルを格納するポインタ。

### 2.1.2 戻り値

成功時は POTR_SUCCESS、失敗時は POTR_ERROR を返します。

### 2.1.3 警告

global が NULL の場合は失敗を返します。
service が NULL の場合は失敗を返します。
handle が NULL の場合は失敗を返します。
POTR_ROLE_RECEIVER かつ callback が NULL の場合は失敗を返します。
POTR_ROLE_SENDER かつ callback が NULL でない場合は失敗を返します。
ただし POTR_TYPE_TCP_BIDIR および POTR_TYPE_UNICAST_BIDIR では SENDER にも
コールバックが必須であり、この場合 callback が NULL の場合は失敗を返します。

### 2.1.4 使用例 (受信者)

    void on_recv(int64_t service_id, PotrPeerId peer_id,
                 PotrEvent event, const void *data, size_t len) {
        (void)peer_id;  // 1:1 モードでは常に POTR_PEER_NA
        if (event == POTR_EVENT_CONNECTED)
            printf("service %" PRId64 ": connected\n", service_id);
        else if (event == POTR_EVENT_DISCONNECTED)
            printf("service %" PRId64 ": disconnected\n", service_id);
        else
            printf("service %" PRId64 ": received %zu bytes\n", service_id, len);
    }

    PotrGlobalConfig global = {0};
    global.window_size        = 16;
    global.max_payload        = 1400;
    global.max_message_size   = 65535;
    global.send_queue_depth   = 64;

    PotrServiceDef service = {0};
    service.service_id = 1001;
    service.type       = POTR_TYPE_UNICAST;
    service.dst_port   = 49001;
    strncpy(service.src_addr[0], "127.0.0.1", POTR_MAX_ADDR_LEN - 1);
    strncpy(service.dst_addr[0], "127.0.0.1", POTR_MAX_ADDR_LEN - 1);

    PotrHandle handle;
    if (potrOpenService(&global, &service,
                        POTR_ROLE_RECEIVER, on_recv, &handle) == POTR_SUCCESS) {
        // 受信待機中 (受信スレッドが動作)
        potrCloseService(handle);
    }

### 2.1.5 使用例 (送信者)

    PotrGlobalConfig global = {0};
    global.window_size        = 16;
    global.max_payload        = 1400;
    global.max_message_size   = 65535;
    global.send_queue_depth   = 64;

    PotrServiceDef service = {0};
    service.service_id = 1001;
    service.type       = POTR_TYPE_UNICAST;
    service.dst_port   = 49001;
    strncpy(service.src_addr[0], "127.0.0.1", POTR_MAX_ADDR_LEN - 1);
    strncpy(service.dst_addr[0], "127.0.0.1", POTR_MAX_ADDR_LEN - 1);

    PotrHandle handle;
    if (potrOpenService(&global, &service,
                        POTR_ROLE_SENDER, NULL, &handle) == POTR_SUCCESS) {
        potrSend(handle, POTR_PEER_NA, "hello", 5, 0);
        potrCloseService(handle);
    }

### 2.1.6 スレッド セーフティ

本関数はスレッドセーフです。
異なるスレッドから独立したハンドルを取得するために並行して呼び出すことができます。
ただし取得したハンドルはスレッドセーフではありません。
同一ハンドルに対する操作は 1 スレッドから行ってください。

## 2.2 potrOpenServiceFromConfig

    POTR_EXPORT int POTR_API potrOpenServiceFromConfig ( const char *config_path, int64_t service_id, PotrRole role, PotrRecvCallback callback, PotrHandle *handle )

設定ファイルから指定サービスを開きます。

設定ファイルを解析してサービス定義を取得し、potrOpenService() を呼び出します。
role と callback の組み合わせが不正な場合は POTR_ERROR を返します。
role と設定ファイルの IP アドレスが不整合 (bind 失敗など) の場合も POTR_ERROR を返します。
通信種別・役割に応じて以下のソケット設定を行います。

通信種別 | 役割 | bind アドレス | bind ポート
--- | --- | --- | ---
POTR_TYPE_UNICAST | 送信者 | src_addr | src_port
POTR_TYPE_UNICAST | 受信者 | dst_addr | dst_port
POTR_TYPE_MULTICAST | 送信者 | INADDR_ANY | src_port
POTR_TYPE_MULTICAST | 受信者 | INADDR_ANY | dst_port
POTR_TYPE_BROADCAST | 送信者 | src_addr | src_port
POTR_TYPE_BROADCAST | 受信者 | INADDR_ANY | dst_port

POTR_ROLE_RECEIVER の場合、内部で受信スレッドを起動します。

### 2.2.1 引数

- config_path [in] 設定ファイルのパス。
- service_id [in] 開くサービスの ID。
- role [in] 役割種別。POTR_ROLE_SENDER または POTR_ROLE_RECEIVER。
- callback [in] イベント発生時に呼び出されるコールバック関数 (PotrRecvCallback)。 POTR_ROLE_RECEIVER の場合は必須。データ受信・接続検知・切断検知を受け取る。 POTR_ROLE_SENDER の場合は通常 NULL を指定すること。
  ただし POTR_TYPE_TCP_BIDIR および POTR_TYPE_UNICAST_BIDIR では SENDER にもコールバックが必須。これらの種別では POTR_ROLE_SENDER でも callback が NULL の場合は失敗を返します。
- handle [out] 成功時にセッションハンドルを格納するポインタ。

### 2.2.2 戻り値

成功時は POTR_SUCCESS、失敗時は POTR_ERROR を返します。

### 2.2.3 警告

handle が NULL の場合は失敗を返します。
config_path が NULL または存在しない場合は失敗を返します。
指定した service_id が設定ファイルに存在しない場合は失敗を返します。
POTR_ROLE_RECEIVER かつ callback が NULL の場合は失敗を返します。
POTR_ROLE_SENDER かつ callback が NULL でない場合は失敗を返します。
ただし POTR_TYPE_TCP_BIDIR および POTR_TYPE_UNICAST_BIDIR では SENDER にも
コールバックが必須であり、この場合 callback が NULL の場合は失敗を返します。

### 2.2.4 使用例 (受信者)

    void on_recv(int64_t service_id, PotrPeerId peer_id,
                 PotrEvent event, const void *data, size_t len) {
        (void)peer_id;  // 1:1 モードでは常に POTR_PEER_NA
        if (event == POTR_EVENT_CONNECTED)
            printf("service %" PRId64 ": connected\n", service_id);
        else if (event == POTR_EVENT_DISCONNECTED)
            printf("service %" PRId64 ": disconnected\n", service_id);
        else
            printf("service %" PRId64 ": received %zu bytes\n", service_id, len);
    }

    PotrHandle handle;
    if (potrOpenServiceFromConfig("porter-services.conf", 1001,
                                  POTR_ROLE_RECEIVER, on_recv, &handle) == POTR_SUCCESS) {
        // 受信待機中 (受信スレッドが動作)
        potrCloseService(handle);
    }

### 2.2.5 使用例 (送信者)

    PotrHandle handle;
    if (potrOpenServiceFromConfig("porter-services.conf", 1001,
                                  POTR_ROLE_SENDER, NULL, &handle) == POTR_SUCCESS) {
        potrSend(handle, POTR_PEER_NA, "hello", 5, 0);
        potrCloseService(handle);
    }

### 2.2.6 スレッド セーフティ

本関数はスレッドセーフです。
異なるスレッドから独立したハンドルを取得するために並行して呼び出すことができます。
ただし取得したハンドルはスレッドセーフではありません。
同一ハンドルに対する操作は 1 スレッドから行ってください。

## 2.3 potrSend

    POTR_EXPORT int POTR_API potrSend ( PotrHandle handle, PotrPeerId peer_id, const void *data, size_t len, int flags )

メッセージを送信します。

フラグ | 説明
--- | ---
`POTR_SEND_COMPRESS` | メッセージを圧縮して送信します。
`POTR_SEND_BLOCKING` | ブロッキング送信を行います。

通信種別に応じて以下の宛先へ UDP パケットを送信します。

通信種別 | 送信先
--- | ---
POTR_TYPE_UNICAST | 接続相手の dst_port 宛にユニキャスト送信
POTR_TYPE_MULTICAST | multicast_group:dst_port へ送信
POTR_TYPE_BROADCAST | broadcast_addr:dst_port へ送信
POTR_TYPE_UNICAST_BIDIR (N:1) | peer_id で指定したピアへ送信

compress に `POTR_SEND_COMPRESS` を指定した場合、内部で圧縮処理を行ってから送信します。
圧縮後のサイズが元のサイズ以上になった場合は、自動的に非圧縮で送信します。
受信側の PotrRecvCallback には、解凍済みの元メッセージが渡されます。
送受信ともにフラグメント化と組み合わせて使用できます。

### 2.3.1 引数

- handle [in] potrOpenService() で取得したセッションハンドル。
- peer_id [in] 送信先ピア識別子。
  N:1 モード: 有効なピア ID (`POTR_PEER_NA` / `POTR_PEER_ALL` 以外) を指定します。
  N:1 モード: POTR_PEER_ALL を指定すると全接続ピアへ一斉送信します。
  N:1 モード: POTR_PEER_NA を指定すると POTR_ERROR を返します。
  1:1 モードおよびその他の通信種別: POTR_PEER_NA または POTR_PEER_ALL を指定します (通常は POTR_PEER_NA を使用)。
- data [in] 送信するメッセージへのポインタ。
- len [in] 送信するメッセージのバイト数。
- flags [in] 送信オプションフラグ。以下のフラグを論理和で組み合わせて指定します。 0 を指定すると非圧縮・ノンブロッキング送信になります。

### 2.3.2 戻り値

成功時は POTR_SUCCESS、失敗時は POTR_ERROR を返します。

### 2.3.3 補足

圧縮フォーマットには raw DEFLATE (RFC 1951) を使用します。
Linux (zlib) と Windows (Compression API MSZIP|COMPRESS_RAW) は 同一フォーマットを出力するため、クロスプラットフォーム通信に対応します。
圧縮効果がない場合 (圧縮後サイズ >= 元サイズ) は、アプリケーションへの通知なしに 内部で非圧縮に切り替えて送信します。送受信のデータ内容に影響はありません。

### 2.3.4 警告

handle が NULL の場合は失敗を返します。
data が NULL の場合は失敗を返します。
len が 0 の場合は失敗を返します。
len が POTR_MAX_MESSAGE_SIZE を超える場合は失敗を返します。
送信スレッドが停止している場合 (potrCloseService 呼び出し後など) は失敗を返します。
N:1 モードで peer_id = POTR_PEER_NA (0) を指定した場合は失敗を返します。
TCP 通信種別 (POTR_TYPE_TCP / POTR_TYPE_TCP_BIDIR) で全 TCP path が切断中に
呼び出した場合は POTR_ERROR_DISCONNECTED (1) を返します
(connect スレッドが非同期に接続を試みている間)。

### 2.3.5 ノンブロッキング送信 (flags に POTR_SEND_BLOCKING を指定しない場合)

メッセージを内部送信キューに登録して即座に返ります。
実際の sendto はバックグラウンド送信スレッドが非同期に実行します。
キューが満杯の場合は空きが生じるまで待機してからメッセージを登録し、登録後に返ります。

### 2.3.6 ブロッキング送信 (flags に POTR_SEND_BLOCKING を指定した場合)

呼び出し前に滞留しているノンブロッキング送信のメッセージが すべて sendto 完了するまで待機します。
その後、本呼び出しのメッセージをキューを通じて sendto して返ります。
本関数が返った時点で、自身のメッセージの sendto は完了しています。

### 2.3.7 スレッド セーフティ

本関数はスレッドセーフではありません。
同一ハンドルへの並行呼び出しは未定義動作です。
送信は 1 スレッドから行ってください。

## 2.4 potrDisconnectPeer

    POTR_EXPORT int POTR_API potrDisconnectPeer ( PotrHandle handle, PotrPeerId peer_id )

指定ピアを切断します (N:1 モード専用)。

指定したピアへ FIN パケットを送信し、ピアのリソースを解放します。
切断完了後に POTR_EVENT_DISCONNECTED コールバックが発火します。
N:1 モード (unicast_bidir かつ src 情報省略) 専用です。
1:1 モードおよびその他の通信種別では POTR_ERROR を返します。

### 2.4.1 引数

- handle [in] potrOpenService() で取得したセッションハンドル。
- peer_id [in] 切断するピアの識別子 (POTR_PEER_NA および POTR_PEER_ALL 以外)。

### 2.4.2 戻り値

成功時は POTR_SUCCESS、失敗時は POTR_ERROR を返します。

### 2.4.3 警告

handle が NULL の場合は失敗を返します。
peer_id = POTR_PEER_NA または POTR_PEER_ALL の場合は失敗を返します。
指定した peer_id が存在しない場合は失敗を返します。
1:1 モードまたは N:1 モード以外で呼び出した場合は失敗を返します。

### 2.4.4 スレッド セーフティ

本関数はスレッドセーフです。
内部で peers_mutex により排他制御されるため、複数スレッドから並行して呼び出せます。
ただし PotrRecvCallback の内部から本関数を呼び出すとデッドロックが発生します。
コールバック内からの呼び出しは避けてください。

## 2.5 potrCloseService

    POTR_EXPORT int POTR_API potrCloseService ( PotrHandle handle )

サービスを閉じます。

受信スレッドを停止し、ソケットをクローズしてリソースを解放します。
マルチキャストの場合はグループから離脱します。
本関数呼び出し後、handle は無効となります。

### 2.5.1 引数

- handle [in] potrOpenService() で取得したセッションハンドル。

### 2.5.2 戻り値

成功時は POTR_SUCCESS、失敗時は POTR_ERROR を返します。

### 2.5.3 補足

本関数呼び出し時、POTR_EVENT_DISCONNECTED コールバックは発火しません。
アプリケーション自身が明示的にサービスを閉じる操作は、接続状態変化イベントとして通知しない設計です。
UDP 通信種別の送信者 (POTR_ROLE_SENDER) が本関数を呼び出した場合は、POTR_FLAG_FIN パケットが送信されます。
TCP 通信種別 (POTR_TYPE_TCP / POTR_TYPE_TCP_BIDIR) では close() による TCP 切断が FIN 相当として機能します。
いずれの場合も、相手側では POTR_EVENT_DISCONNECTED が発火します。

### 2.5.4 警告

handle が NULL の場合は失敗を返します。

### 2.5.5 スレッド セーフティ

本関数はスレッドセーフではありません。
同一ハンドルに対して他の porter API と並行して呼び出さないでください。
本関数を呼び出す前に、同一ハンドルへのすべての potrSend() が完了していることを確認してください。

## 2.6 potrLogConfig

    POTR_EXPORT int POTR_API potrLogConfig ( PotrLogLevel level, const char *log_file, int console )

ロガーを設定します。

本関数は potrOpenService() の前に呼び出してください。
複数回呼び出した場合は最後の設定が有効になります。

### 2.6.1 引数

- level [in] 出力する最低ログレベル。POTR_TRACE_NONE でログ無効 (デフォルト)。
- log_file [in] ログファイルのパス。NULL または空文字列を指定するとファイル出力なし。
- console [in] 0 以外を指定すると標準エラー出力 (stderr) にも出力します。

### 2.6.2 戻り値

成功時は POTR_SUCCESS、log_file が開けない場合は POTR_ERROR を返します。

### 2.6.3 警告

log_file に指定したパスが書き込み不可の場合は POTR_ERROR を返します。

### 2.6.4 出力先

OS | 出力先
--- | ---
Linux | syslog (trace-util 経由)、ログファイル (trace-util 経由、log_file 指定時)、stderr (trace-util 経由、console 指定時)
Windows | ETW (trace-util 経由)、ログファイル (trace-util 経由、log_file 指定時)、stderr (trace-util 経由、console 指定時)

### 2.6.5 ログフォーマット

OS トレース (syslog / ETW) およびファイルへの出力フォーマット:

    [file.c:line] message

stderr への出力フォーマット (タイムスタンプは UTC、L はレベル文字):

    YYYY-MM-DD HH:MM:SS.mmm L [file.c:line] message

### 2.6.6 ログレベル一覧

レベル | 値 | 出力内容
--- | --- | ---
POTR_TRACE_CRITICAL | 0 | 致命的エラー
POTR_TRACE_ERROR | 1 | 操作失敗
POTR_TRACE_WARNING | 2 | NACK・REJECT・回復可能な異常
POTR_TRACE_INFO | 3 | サービス開始・終了・接続状態変化
POTR_TRACE_VERBOSE | 4 | ソケット操作・設定値・パケット送受信・スレッド動作
POTR_TRACE_NONE | 5 | ログ無効 (デフォルト)

### 2.6.7 使用例

    // INFO 以上をファイルと stderr に出力
    potrLogConfig(POTR_TRACE_INFO, "/var/log/porter.log", 1);

    // VERBOSE 以上をファイルのみに出力
    potrLogConfig(POTR_TRACE_VERBOSE, "/tmp/porter.log", 0);

    // ログを無効化
    potrLogConfig(POTR_TRACE_NONE, NULL, 0);

### 2.6.8 スレッド セーフティ

本関数はスレッドセーフです。
出力制御は trace-util が内部で排他制御を行うため、ログを出力中のスレッドが存在する場合でも 安全に設定を変更できます。

## 2.7 potrGetServiceType

    POTR_EXPORT int POTR_API potrGetServiceType ( const char *config_path, int64_t service_id, PotrType *type )

設定ファイルから指定サービスの通信種別を取得します。

設定ファイルを解析して指定サービスの通信種別を返します。
potrOpenService() の前に呼び出すことで、ロール・コールバックの要否を アプリケーション側で判断できます。
本関数はソケットの作成や通信スレッドの起動を行いません。

### 2.7.1 引数

- config_path [in] 設定ファイルのパス。
- service_id [in] 照会するサービスの ID。
- type [out] 成功時に通信種別 (PotrType) を格納するポインタ。

### 2.7.2 戻り値

成功時は POTR_SUCCESS、失敗時は POTR_ERROR を返します。

### 2.7.3 警告

config_path または type が NULL の場合は失敗を返します。
指定した service_id が設定ファイルに存在しない場合は失敗を返します。

### 2.7.4 使用例

    PotrType type;
    if (potrGetServiceType("porter-services.conf", 1031, &type) == POTR_SUCCESS) {
        if (type == POTR_TYPE_UNICAST_BIDIR) {
            // unicast_bidir: コールバックが必須
            potrOpenService("porter-services.conf", 1031,
                            POTR_ROLE_SENDER, on_recv, &handle);
        }
    }

### 2.7.5 スレッド セーフティ

本関数はスレッドセーフです。
グローバルな共有状態にアクセスしないため、複数スレッドから並行して呼び出せます。

# 3 定数、マクロ

## 3.1 POTR_EXPORT

    #define POTR_EXPORT

DLL エクスポート/インポート制御マクロ。

ビルド条件に応じて以下の値を取ります。

条件 | 値
--- | ---
Linux (非 Windows) | (空)
Windows / `__INTELLISENSE__` 定義時 | (空)
Windows / `POTR_STATIC` 定義時 (静的リンク) | (空)
Windows / `POTR_EXPORTS` 定義時 (DLL ビルド) | `__declspec(dllexport)`
Windows / `POTR_EXPORTS` 未定義時 (DLL 利用側) | `__declspec(dllimport)`

## 3.2 POTR_API

    #define POTR_API

呼び出し規約マクロ。

Windows 環境では `__stdcall` 呼び出し規約を指定します。
Linux (非 Windows) 環境では空に展開されます。
既に定義済みの場合は再定義されません。