19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
50 struct sockaddr_in addr;
53 sock = socket(AF_INET, SOCK_DGRAM, 0);
60 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
62 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
63 (
const char *)&reuse,
sizeof(reuse));
66 memset(&addr, 0,
sizeof(addr));
67 addr.sin_family = AF_INET;
68 addr.sin_addr = bind_addr;
69 addr.sin_port = htons(port);
71 if (bind(sock, (
struct sockaddr *)&addr,
sizeof(addr)) < 0)
90 srand((
unsigned)((
unsigned long)time(NULL) ^ (
unsigned long)getpid()));
93 clock_gettime(CLOCK_REALTIME, &ts);
100 srand((
unsigned)(GetTickCount() ^ GetCurrentProcessId()));
103 GetSystemTimeAsFileTime(&ft);
104 uli.LowPart = ft.dwLowDateTime;
105 uli.HighPart = ft.dwHighDateTime;
107 ctx->
session_tv_sec = (int64_t)(uli.QuadPart / 10000000ULL) - 11644473600LL;
108 ctx->
session_tv_nsec = (int32_t)((uli.QuadPart % 10000000ULL) * 100ULL);
116 struct in_addr src_if,
120 struct sockaddr_in addr;
134 sock = socket(AF_INET, SOCK_DGRAM, 0);
141 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
143 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
144 (
const char *)&reuse,
sizeof(reuse));
147 memset(&addr, 0,
sizeof(addr));
148 addr.sin_family = AF_INET;
149 addr.sin_addr.s_addr = htonl(INADDR_ANY);
150 addr.sin_port = htons(bind_port);
152 if (bind(sock, (
struct sockaddr *)&addr,
sizeof(addr)) < 0)
163 memset(&mreq, 0,
sizeof(mreq));
173 mreq.imr_interface = src_if;
176 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
177 &mreq,
sizeof(mreq)) < 0)
183 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
184 (
const char *)&mreq,
sizeof(mreq)) < 0)
195 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
196 &src_if,
sizeof(src_if));
198 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
199 (
const char *)&src_if,
sizeof(src_if));
213 struct in_addr src_if,
217 struct sockaddr_in addr;
224 bind_port = dst_port;
228 bind_port = src_port;
231 sock = socket(AF_INET, SOCK_DGRAM, 0);
238 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
239 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast,
sizeof(bcast));
241 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
242 (
const char *)&reuse,
sizeof(reuse));
243 setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
244 (
const char *)&bcast,
sizeof(bcast));
247 memset(&addr, 0,
sizeof(addr));
248 addr.sin_family = AF_INET;
252 addr.sin_addr.s_addr = src_if.s_addr;
256 addr.sin_addr.s_addr = htonl(INADDR_ANY);
258 addr.sin_port = htons(bind_port);
260 if (bind(sock, (
struct sockaddr *)&addr,
sizeof(addr)) < 0)
284 closesocket(ctx->
sock[i]);
346 struct sockaddr_in addr;
348 struct in_addr bind_ip;
360 bind_ip.s_addr = htonl(INADDR_ANY);
372 sock = socket(AF_INET, SOCK_STREAM, 0);
379 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
381 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
382 (
const char *)&reuse,
sizeof(reuse));
385 memset(&addr, 0,
sizeof(addr));
386 addr.sin_family = AF_INET;
387 addr.sin_addr = bind_ip;
390 if (bind(sock, (
struct sockaddr *)&addr,
sizeof(addr)) < 0)
400 if (listen(sock, SOMAXCONN) < 0)
422 "open_socket_tcp_sender: dst_addr[%d] is empty", path_idx);
456 "potrOpenService: invalid argument (global=%p service=%p handle=%p)",
457 (
const void *)
global, (
const void *)
service, (
const void *)handle);
462 "potrOpenService: service_id=%" PRId64
" role=%d",
469 "potrOpenService: service_id=%" PRId64
" RECEIVER role requires callback",
478 "potrOpenService: service_id=%" PRId64
" unknown role=%d",
486 if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
498 memset(ctx, 0,
sizeof(*ctx));
520 "potrOpenService: service_id=%" PRId64
" SENDER role must not have callback"
530 "potrOpenService: service_id=%" PRId64
" UNICAST_BIDIR SENDER role requires callback",
540 "potrOpenService: service_id=%" PRId64
" invalid max_payload=%u (range: 64..%u)",
548 "potrOpenService: service_id=%" PRId64
" invalid window_size=%u (range: 2..%u)",
556 "potrOpenService: service_id=%" PRId64
" max_message_size=%u must be >= max_payload=%u",
565 "potrOpenService: service_id=%" PRId64
" invalid send_queue_depth=%u (min: 2)",
588 "potrOpenService: service_id=%" PRId64
" type=%d window=%u max_payload=%u"
589 " max_message_size=%u send_queue_depth=%u"
590 " health_interval=%ums health_timeout=%ums",
612 struct in_addr bind_addr;
714 const char *dflt =
"255.255.255.255";
715 size_t len = strlen(dflt);
759 "potrOpenService: service_id=%" PRId64
" UNICAST_BIDIR requires"
760 " dst_port (non-zero)",
770 struct in_addr bind_addr;
774 bind_addr.s_addr = htonl(INADDR_ANY);
794 "potrOpenService: service_id=%" PRId64
" UNICAST_BIDIR 1:1 dynamic RECEIVER"
807 struct in_addr bind_addr;
838 bind_addr.s_addr = htonl(INADDR_ANY);
877 "potrOpenService: service_id=%" PRId64
" UNICAST_BIDIR_N1 requires"
878 " dst_port (non-zero)",
887 struct in_addr any_addr;
888 any_addr.s_addr = htonl(INADDR_ANY);
902 struct in_addr bind_addr;
936 "potrOpenService: service_id=%" PRId64
" UNICAST_BIDIR_N1"
937 " (max_peers=%d src_port_filter=%u) bind dst_port=%u n_path=%d",
951 "potrOpenService: service_id=%" PRId64
" TCP requires dst_port",
968 "potrOpenService: service_id=%" PRId64
" TCP listen failed"
969 " (path=%d dst_addr=%s dst_port=%u)",
977 "potrOpenService: service_id=%" PRId64
" TCP path[%d] listening"
987 "potrOpenService: service_id=%" PRId64
" TCP RECEIVER requires"
988 " at least one dst_addr",
1005 "potrOpenService: service_id=%" PRId64
" TCP sender"
1006 " dst_addr resolve failed (path=%d %s)",
1016 "potrOpenService: service_id=%" PRId64
" TCP SENDER requires"
1017 " at least one dst_addr",
1050 for (i = 0; i < ctx->
n_path; i++)
1070 for (i = 0; i < ctx->
n_path; i++)
1081 struct in_addr mcast_ip;
1087 for (i = 0; i < ctx->
n_path; i++)
1099 struct in_addr bcast_ip;
1105 for (i = 0; i < ctx->
n_path; i++)
1336 const char *role_str;
1339 role_str =
"SENDER";
1343 role_str =
"RECEIVER";
1346 "potrOpenService: service_id=%" PRId64
" role=%s encrypt=%s opened successfully",
#define POTR_COMPRESS_HEADER_SIZE
圧縮ペイロード先頭に付加する元サイズフィールドのバイト数。
#define POTR_CRYPTO_TAG_SIZE
AES-256-GCM 認証タグサイズ (バイト)。暗号文の直後に付加する。
#define POTR_MAX_WINDOW_SIZE
ウィンドウサイズの最大値 (パケット数)。window_size 設定値のバリデーション上限として使用する。
#define POTR_MAX_PATH
マルチパスの最大パス数。
#define POTR_MAX_PAYLOAD
ペイロードの最大長 (バイト)。UDP 最大ペイロード (65535 - IP20 - UDP8)。max_payload 設定値のバリデーション上限として使用する。
#define POTR_SUCCESS
成功の戻り値を表す定数。
#define POTR_ERROR
失敗の戻り値を表す定数。
#define PACKET_HEADER_SIZE
パケットヘッダーの固定長 (バイト)。payload フィールドの開始オフセット。
通信ライブラリ (動的リンク用) のヘッダーファイル。
#define POTR_API
呼び出し規約マクロ。
#define POTR_EXPORT
DLL エクスポート/インポート制御マクロ。
@ POTR_TRACE_ERROR
エラー。操作の失敗を記録。TRACE_LV_ERROR (1) と同値。
@ POTR_TRACE_INFO
情報。TRACE_LV_INFO (3) と同値。
@ POTR_TRACE_VERBOSE
詳細情報 (デバッグ)。TRACE_LV_VERBOSE (4) と同値。
void(* PotrRecvCallback)(int64_t service_id, PotrPeerId peer_id, PotrEvent event, const void *data, size_t len)
受信コールバック関数型 (全通信種別共通)。
@ POTR_TYPE_BROADCAST_RAW
1:N 通信 RAW モード (UDP ブロードキャスト)。
@ POTR_TYPE_BROADCAST
1:N 通信 (UDP ブロードキャスト)。
@ POTR_TYPE_UNICAST_BIDIR_N1
N:1 双方向通信 (UDP ユニキャスト)。
@ POTR_TYPE_UNICAST
1:1 通信 (UDP ユニキャスト)。
@ POTR_TYPE_MULTICAST_RAW
1:N 通信 RAW モード (UDP マルチキャスト)。
@ POTR_TYPE_TCP_BIDIR
TCP 双方向通信 (両端が potrSend 可)。
@ POTR_TYPE_TCP
TCP ユニキャスト通信 (単方向: SENDER のみ potrSend 可)。
@ POTR_TYPE_UNICAST_RAW
1:1 通信 RAW モード (UDP ユニキャスト)。
@ POTR_TYPE_UNICAST_BIDIR
双方向 1:1 通信 (UDP ユニキャスト)。
@ POTR_TYPE_MULTICAST
1:N 通信 (UDP マルチキャスト)。
struct PotrContext_ * PotrHandle
セッションハンドル。
int potr_connect_thread_start(struct PotrContext_ *ctx)
TCP 接続管理スレッドを起動します (path 数分)。
#define POTR_INVALID_SOCKET
static PotrType potr_raw_base_type(PotrType t)
RAW 系通信種別をベース通信種別に変換する (非 RAW 型はそのまま返す)。
static int potr_is_tcp_type(PotrType t)
TCP 通信種別 (POTR_TYPE_TCP / POTR_TYPE_TCP_BIDIR) か判定する。
int potr_health_thread_start(struct PotrContext_ *ctx)
非 TCP ヘルスチェックスレッドを起動します。
int potr_health_thread_stop(struct PotrContext_ *ctx)
非 TCP ヘルスチェックスレッドを停止します。
int parse_ipv4_addr(const char *ip_str, struct in_addr *out_addr)
int resolve_ipv4_addr(const char *host, struct in_addr *out_addr)
ホスト名または IPv4 アドレス文字列を struct in_addr に解決する。
IPv4 アドレス変換ユーティリティ (内部用)。
#define POTR_LOG(level,...)
porter 内部ログ出力マクロ。
static void generate_session(struct PotrContext_ *ctx)
static PotrSocket open_socket_broadcast(uint16_t src_port, uint16_t dst_port, struct in_addr src_if, int is_receiver)
static int open_socket_tcp_receiver(struct PotrContext_ *ctx, int path_idx)
static PotrSocket open_socket_multicast(const PotrServiceDef *def, struct in_addr src_if, int is_receiver)
static int open_socket_tcp_sender(struct PotrContext_ *ctx, int path_idx)
static PotrSocket open_socket_unicast(struct in_addr bind_addr, uint16_t port)
static void ctx_cleanup(struct PotrContext_ *ctx)
POTR_EXPORT int POTR_API potrOpenService(const PotrGlobalConfig *global, const PotrServiceDef *service, PotrRole role, PotrRecvCallback callback, PotrHandle *handle)
設定構造体から指定サービスを開きます。
static void cleanup_sockets(struct PotrContext_ *ctx)
void peer_table_destroy(struct PotrContext_ *ctx)
ピアテーブルを破棄する。
int peer_table_init(struct PotrContext_ *ctx)
ピアテーブルを初期化する。
N:1 モード用ピアテーブル管理モジュールの内部ヘッダー。
int comm_recv_thread_start(struct PotrContext_ *ctx)
非 TCP 受信スレッドを起動します。
int potr_send_queue_init(PotrSendQueue *q, size_t depth, uint16_t max_payload)
void potr_send_queue_destroy(PotrSendQueue *q)
int potr_send_thread_start(struct PotrContext_ *ctx)
void potr_send_thread_stop(struct PotrContext_ *ctx)
セッションコンテキスト構造体。PotrHandle の実体。
uint32_t session_id
自セッション識別子 (乱数)。
PotrRecvCallback callback
受信コールバック。
PotrGlobalConfig global
グローバル設定。
struct in_addr dst_addr_resolved[POTR_MAX_PATH]
解決済み宛先 IPv4 アドレス (unicast のみ)。
size_t compress_buf_size
compress_buf のサイズ (バイト)。
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 バイト)。送信スレッドのみ使用。
PotrMutex tcp_send_mutex[POTR_MAX_PATH]
TCP send() 排他制御 (path ごと)。送信スレッド・ヘルスチェックスレッド・recv スレッド競合防止。
PotrMutex tcp_state_mutex
tcp_state_cv 保護用ミューテックス。tcp_active_paths のカウンタ更新も保護。
PotrSocket tcp_listen_sock[POTR_MAX_PATH]
RECEIVER: listen ソケット (path ごと)。
int is_multi_peer
1: N:1 モード (src_addr/src_port 省略), 0: 1:1 モード。
PotrServiceDef service
サービス定義。
PotrMutex health_mutex[POTR_MAX_PATH]
ヘルスチェックスレッド停止用ミューテックス (path ごと)。
size_t crypto_buf_size
crypto_buf のサイズ (バイト)。
PotrSocket sock[POTR_MAX_PATH]
各パスの UDP ソケット。
PotrWindow send_window
送信バッファ (過去 N パケット保持。NACK 再送・REJECT 判定に使用)。
int max_peers
ピアテーブルサイズ (service.max_peers から取得)。
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
自セッション開始時刻 秒部。
PotrPeerContext * peers
ピアテーブル (動的確保。max_peers エントリ)。
PotrSocket tcp_conn_fd[POTR_MAX_PATH]
アクティブ TCP 接続 fd (path ごと)。
uint32_t tcp_health_interval_ms
TCP 通信種別の PING 送信間隔 (ミリ秒)。DATA 送信頻度に関わらず定期的に PING を送信。0 = 無効。設定ファイルキー: tcp_health_interval_ms。
uint16_t window_size
スライディングウィンドウサイズ (パケット数)。
uint32_t send_queue_depth
非同期送信キューの最大エントリ数。デフォルト: POTR_SEND_QUEUE_DEPTH。
uint32_t tcp_health_timeout_ms
TCP 通信種別の PING 応答待機タイムアウト (ミリ秒)。SENDER 側で使用。0 = 無効。設定ファイルキー: tcp_health_timeout_ms。
uint16_t max_payload
最大ペイロード長 (バイト)。
uint32_t health_interval_ms
UDP 通信種別の PING 送信間隔 (ミリ秒)。最終 DATA/PING 送信から本値が経過したら PING 送信。0 = 無効。設定ファイルキー: udp_health_interval_ms。
uint32_t health_timeout_ms
UDP 通信種別の受信タイムアウト (ミリ秒)。RECEIVER 側で使用。0 = 無効。設定ファイルキー: udp_health_timeout_ms。
uint32_t max_message_size
1 回の potrSend で送信できる最大メッセージ長 (バイト)。デフォルト: POTR_MAX_MESSAGE_SIZE。
uint16_t src_port
送信者の送信元 bind ポート番号。0 = OS 自動選定。(全通信種別で省略可)
uint32_t health_interval_ms
グローバルの udp/tcp_health_interval_ms をサービス単位で上書きする。0 = グローバル値を使用。
int encrypt_enabled
非 0 のとき暗号化有効。設定ファイルに有効な encrypt_key が存在するときに 1 に設定される。
uint16_t dst_port
宛先ポート番号。サービスの識別子。受信者の bind ポート / 送信者の送信先ポート。(全通信種別で必須)
char src_addr[POTR_MAX_PATH][POTR_MAX_ADDR_LEN]
送信元アドレス [0]=src_addr1 〜 [3]=src_addr4。送信者は bind / 送信インターフェース、受信者は送信元フィルタ。(全通信種別で必須)
char multicast_group[POTR_MAX_ADDR_LEN]
マルチキャストグループアドレス。(multicast のみ)
int64_t service_id
サービス ID。
char dst_addr[POTR_MAX_PATH][POTR_MAX_ADDR_LEN]
宛先アドレス [0]=dst_addr1 〜 [3]=dst_addr4。送信者は送信先、受信者は bind アドレス。(unicast のみ)
uint32_t max_peers
N:1 モード時の最大同時接続ピア数。省略時: 1024。1:1 モードでは無視される。
char broadcast_addr[POTR_MAX_ADDR_LEN]
ブロードキャスト宛先アドレス。省略時は 255.255.255.255。(broadcast のみ)
uint32_t health_timeout_ms
グローバルの udp/tcp_health_timeout_ms をサービス単位で上書きする。0 = グローバル値を使用。
int window_init(PotrWindow *win, uint32_t initial_seq, uint16_t window_size, uint16_t max_payload)
ウィンドウを初期化します。
void window_destroy(PotrWindow *win)
ウィンドウが保持する動的確保バッファを解放します。
スライディングウィンドウ管理モジュールの内部ヘッダー。