Newer
Older
libkc / modules / src / kc_socket.c
  1. /**
  2. * @file kc_socket.c
  3. * @brief ソケットモジュール
  4. * @copyright 2003 - 2024 Nomura Kei
  5. */
  6. #include <stdio.h>
  7.  
  8. #include <string.h>
  9. #include <errno.h>
  10.  
  11. #include <kc.h>
  12. #include <kc_lock_guard.h>
  13. #include <kc_memory.h>
  14. #include <kc_socket.h>
  15.  
  16. #if (KC_IS_WINDOWS)
  17. // Windows の setsockopt に指定する値は、様々な型のデータを渡すにもかかわらず、
  18. // const char* 型と定義されているため、明示的にキャストする。
  19. #define setsockopt(sockfd, level, optname, optval, optlen) \
  20. setsockopt(sockfd, level, optname, (const char *)optval, optlen)
  21. #endif // KC_IS_WINDOWS
  22.  
  23. /**
  24. * KcSocket 管理情報
  25. */
  26. typedef struct
  27. {
  28. socket_t sock_fd; //!< ソケットディスクリプタ
  29. int sock_type; //!< ソケットタイプ
  30. int sock_family; //!< ソケットファミリ
  31. struct sockaddr_storage remote_addr; //!< リモートアドレス
  32. struct sockaddr_storage local_addr; //!< ローカルアドレス
  33. socklen_t remote_addrlen; //!< リモートアドレス長
  34. socklen_t local_addrlen; //!< ローカルアドレス長
  35. char tmp_remote_host[NI_MAXHOST]; //!< 一時的なリモートホスト名格納用
  36. char tmp_local_host[NI_MAXHOST]; //!< 一時的なローカルホスト名格納用
  37. const char *mcast_v4_ifname; //!< マルチキャスト ifname (IPv4)
  38. const char *mcast_v6_ifname; //!< マルチキャスト ifname (IPv6)
  39. } KcSocketInfo;
  40.  
  41. /**
  42. * アドレス情報
  43. */
  44. typedef struct
  45. {
  46. const char *addr; //!< アドレス
  47. const char *service; //!< サービス
  48. } KcSocketAddress;
  49.  
  50. // =============================================================================
  51. // プロトタイプ宣言
  52. // =============================================================================
  53. static void Socket_setup(void);
  54. static void Socket_cleanup(void);
  55. static const char *KcSocket_get_remote_addr(KcSocket *sock);
  56. static int KcSocket_get_remote_port(KcSocket *sock);
  57. static const char *KcSocket_get_local_addr(KcSocket *sock);
  58. static int KcSocket_get_local_port(KcSocket *sock);
  59. static socket_t KcSocket_get_socket(KcSocket *sock);
  60. static int KcSocket_get_type(KcSocket *sock);
  61. static int KcSocket_get_family(KcSocket *sock);
  62. static bool KcSocket_get_addrinfo(KcSocket *sock, struct addrinfo **result, const char *addr, const char *service, bool is_passive);
  63. static bool KcSocket_bind(KcSocket *sock, const char *addr, const char *service);
  64. static bool KcSocket_listen(KcSocket *sock, int backlog);
  65. static KcSocket *KcSocket_accept(KcSocket *sock);
  66. static bool KcSocket_connect(KcSocket *sock, const char *addr, const char *service, const char *local_addr, const char *local_service);
  67. static bool KcSocket_close(KcSocket *sock);
  68. static ssize_t KcSocket_send(KcSocket *sock, const char *buff, size_t size, int flags);
  69. static ssize_t KcSocket_recv(KcSocket *sock, char *buff, size_t size, int flags);
  70. static ssize_t KcSocket_sendto(KcSocket *sock, const char *buff, size_t size, int flags, const char *addr, const char *service);
  71. static ssize_t KcSocket_recvfrom(KcSocket *sock, char *buff, size_t size, int flags, char *src_addr, size_t src_addrlen, char *src_service, size_t src_servicelen);
  72. static bool KcSocket_set_ttl(KcSocket *sock, int val);
  73. static bool KcSocket_join(KcSocket *sock, const char *addr, const char *ifname);
  74. static bool KcSocket_leave(KcSocket *sock, const char *addr, const char *ifname);
  75. static void KcSocket_set_ifname(KcSocket *sock, const char *v4_ifname, const char *v6_ifname);
  76. static void KcSocket_print_info(KcSocket *sock, char *buff, size_t size);
  77.  
  78. // 内部関数
  79. static bool KcSocket_addrinfo_bind_and_connect(
  80. KcSocket *sock, struct addrinfo *bind_addrinfo, struct addrinfo *conn_addrinfo);
  81. static bool KcSocket_addrinfo_connect(KcSocket *sock, struct addrinfo *conn_addrinfo, socket_t sockfd);
  82. static int KcSocket_join_ipv4(KcSocket *sock, const char *addr, const char *ifname);
  83. static int KcSocket_join_ipv6(KcSocket *sock, const char *addr, const char *ifname);
  84. static int KcSocket_leave_ipv4(KcSocket *sock, const char *addr, const char *ifname);
  85. static int KcSocket_leave_ipv6(KcSocket *sock, const char *addr, const char *ifname);
  86. static bool KcSocket_set_mcastif(socket_t tmp_sock, int family, const char* mcast_v4_ifname, const char* mcast_v6_ifname);
  87. static int KcSocket_set_mcastif_ipv4(socket_t tmp_sock, const char *ifname);
  88. static int KcSocket_set_mcastif_ipv6(socket_t tmp_sock, const char *ifname);
  89. static int KcSocket_print_addr(char *buff, size_t size, const struct sockaddr *addr, size_t addrlen);
  90.  
  91. /**
  92. * ソケットのセットアップをします。
  93. */
  94. static void Socket_setup(void)
  95. {
  96. static bool is_init = false;
  97. if (!is_init)
  98. {
  99. #if (KC_IS_WINDOWS)
  100. WSADATA wsa_data;
  101. WSAStartup(MAKEWORD(2, 0), &wsa_data);
  102. #endif
  103. atexit(Socket_cleanup);
  104. is_init = true;
  105. }
  106. }
  107.  
  108. /**
  109. * ソケットライブラリのクリーンアップをします。
  110. */
  111. static void Socket_cleanup(void)
  112. {
  113. #if (KC_IS_WINDOWS)
  114. WSACleanup();
  115. #endif
  116. }
  117.  
  118. // =============================================================================
  119. // new
  120. // =============================================================================
  121. /**
  122. * 指定されたタイプ、ファミリのSocket オブジェクトを構築します。
  123. *
  124. * @param type タイプ(SOCK_STREAM/SOCK_DGRAM/SOCK_RAW)
  125. * @param family ファミリ(AF_UNSPEC/AF_INET/AF_INET6)
  126. */
  127. KcSocket *KcSocket_new(int type, int family)
  128. {
  129. // KcSocket の管理構造
  130. // +----------------+
  131. // | KcSocket |
  132. // | ... |
  133. // | _info -----------+
  134. // +----------------+ |
  135. // | <KcSocketInfo> |<--+
  136. // +----------------+
  137. Socket_setup();
  138. KcSocket *sock = (KcSocket *)malloc(sizeof(KcSocket) + sizeof(KcSocketInfo));
  139. if (sock != NULL)
  140. {
  141. sock->get_remote_addr = KcSocket_get_remote_addr;
  142. sock->get_remote_port = KcSocket_get_remote_port;
  143. sock->get_local_addr = KcSocket_get_local_addr;
  144. sock->get_local_port = KcSocket_get_local_port;
  145. sock->get_socket = KcSocket_get_socket;
  146. sock->get_type = KcSocket_get_type;
  147. sock->get_family = KcSocket_get_family;
  148. sock->get_addrinfo = KcSocket_get_addrinfo; // for local
  149. sock->bind = KcSocket_bind;
  150. sock->listen = KcSocket_listen;
  151. sock->accept = KcSocket_accept;
  152. sock->connect = KcSocket_connect;
  153. sock->close = KcSocket_close;
  154. sock->send = KcSocket_send;
  155. sock->recv = KcSocket_recv;
  156. sock->sendto = KcSocket_sendto;
  157. sock->recvfrom = KcSocket_recvfrom;
  158. sock->set_ttl = KcSocket_set_ttl;
  159. sock->join = KcSocket_join;
  160. sock->leave = KcSocket_leave;
  161. sock->set_ifname = KcSocket_set_ifname;
  162. sock->print_info = KcSocket_print_info;
  163. sock->_info = (sock + 1);
  164. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  165. info->sock_fd = INVALID_SOCKET;
  166. info->sock_type = type;
  167. info->sock_family = family;
  168. info->remote_addrlen = 0;
  169. info->local_addrlen = 0;
  170. info->tmp_local_host[0] = '\0';
  171. info->tmp_remote_host[0] = '\0';
  172. info->mcast_v4_ifname = NULL;
  173. info->mcast_v6_ifname = NULL;
  174. }
  175. return sock;
  176. }
  177.  
  178. // =============================================================================
  179. // delete
  180. // =============================================================================
  181. /**
  182. * Socket を破棄します。
  183. */
  184. void KcSocket_delete(KcSocket *socket)
  185. {
  186. if (socket)
  187. {
  188. if (((KcSocketInfo *)socket->_info)->sock_fd != INVALID_SOCKET)
  189. {
  190. socket->close(socket);
  191. }
  192. free(socket);
  193. }
  194. }
  195.  
  196. // =============================================================================
  197. // get_remote_addr
  198. // =============================================================================
  199. /**
  200. * ソケットの接続先アドレスを返します。
  201. * アドレスが取得できない場合(未接続状態など)、NULL を返します。
  202. *
  203. * @param sock 対象ソケット
  204. * @return ソケットの接続先アドレス
  205. */
  206. static const char *KcSocket_get_remote_addr(KcSocket *sock)
  207. {
  208. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  209. if (info->remote_addrlen)
  210. {
  211. int ret = getnameinfo(
  212. (const struct sockaddr *)&info->remote_addr,
  213. info->remote_addrlen,
  214. info->tmp_remote_host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  215. if (ret == 0)
  216. {
  217. return info->tmp_remote_host;
  218. }
  219. }
  220. return NULL;
  221. }
  222.  
  223. /**
  224. * ソケットの接続先ポート番号を返します。
  225. * 接続先ポート番号が取得できなかった場合、-1 を返します。
  226. *
  227. * @param sock 対象ソケット
  228. * @return ポート番号
  229. */
  230. static int KcSocket_get_remote_port(KcSocket *sock)
  231. {
  232. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  233. if (info->remote_addrlen)
  234. {
  235. char tmp_port[NI_MAXSERV];
  236. int ret = getnameinfo(
  237. (const struct sockaddr *)&info->remote_addr,
  238. info->remote_addrlen,
  239. NULL, 0, tmp_port, sizeof(tmp_port), NI_NUMERICSERV);
  240. if (ret == 0)
  241. {
  242. return atoi(tmp_port);
  243. }
  244. }
  245. return -1;
  246. }
  247.  
  248. /**
  249. * ソケットのローカルアドレスを返します。
  250. * アドレスが取得できない場合、NULL を返します。
  251. *
  252. * @param sock 対象ソケット
  253. * @return ソケットのローカルアドレス
  254. */
  255. static const char *KcSocket_get_local_addr(KcSocket *sock)
  256. {
  257. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  258. if (info->local_addrlen)
  259. {
  260. int ret = getnameinfo(
  261. (const struct sockaddr *)&info->local_addr,
  262. info->local_addrlen,
  263. info->tmp_local_host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  264. if (ret == 0)
  265. {
  266. return info->tmp_local_host;
  267. }
  268. }
  269. return NULL;
  270. }
  271.  
  272. /**
  273. * ソケットのローカルポート番号を返します。
  274. * ローカルポート番号が取得できなかった場合、-1 を返します。
  275. *
  276. * @param sock 対象ソケット
  277. * @return ポート番号
  278. */
  279. static int KcSocket_get_local_port(KcSocket *sock)
  280. {
  281. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  282. if (info->local_addrlen)
  283. {
  284. char tmp_port[NI_MAXSERV];
  285. int ret = getnameinfo(
  286. (const struct sockaddr *)&info->local_addr,
  287. info->local_addrlen,
  288. NULL, 0, tmp_port, sizeof(tmp_port), NI_NUMERICSERV);
  289. if (ret == 0)
  290. {
  291. return atoi(tmp_port);
  292. }
  293. }
  294. return -1;
  295. }
  296.  
  297. /**
  298. * ソケットディスクリプタを返します。
  299. * 通常は、ソケットディスクリプタを直接操作しないでください。
  300. *
  301. * @param sock 対象ソケット
  302. * @return ソケットディスクリプタ
  303. */
  304. static socket_t KcSocket_get_socket(KcSocket *sock)
  305. {
  306. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  307. return info->sock_fd;
  308. }
  309.  
  310. /**
  311. * ソケットタイプを返します。
  312. *
  313. * @param sock 対象ソケット
  314. * @return ソケットタイプ
  315. */
  316. static int KcSocket_get_type(KcSocket *sock)
  317. {
  318. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  319. return info->sock_type;
  320. }
  321.  
  322. /**
  323. * ソケットファミリを返します。
  324. * ソケット接続、バインド時には、実際にバインド、
  325. * あるいは接続されているソケットファミリを返します。
  326. *
  327. * @param sock 対象ソケット
  328. * @return ソケットファミリ
  329. */
  330. static int KcSocket_get_family(KcSocket *sock)
  331. {
  332. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  333. int result_family = info->sock_family;
  334. if (info->sock_fd != INVALID_SOCKET)
  335. {
  336. struct sockaddr_storage ss;
  337. socklen_t len = sizeof(struct sockaddr_storage);
  338. if (getsockname(info->sock_fd, (struct sockaddr *)&ss, &len) == 0)
  339. {
  340. result_family = ss.ss_family;
  341. }
  342. }
  343. return result_family;
  344. }
  345.  
  346. /**
  347. * 指定されたアドレス、サービスのアドレス情報を取得します。
  348. *
  349. * @param sock 対象ソケット
  350. * @param result アドレス情報格納用ポインタ
  351. * @param addr アドレス
  352. * @param service サービス
  353. * @param is_passive サーバソケットの場合、true を指定ください。
  354. */
  355. static bool KcSocket_get_addrinfo(
  356. KcSocket *sock, struct addrinfo **result,
  357. const char *addr, const char *service, bool is_passive)
  358. {
  359. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  360.  
  361. struct addrinfo hints;
  362. memset(&hints, 0x00, sizeof(struct addrinfo));
  363. hints.ai_socktype = info->sock_type;
  364. hints.ai_family = info->sock_family;
  365. if (is_passive)
  366. {
  367. hints.ai_flags = AI_PASSIVE;
  368. }
  369. int ret = getaddrinfo(addr, service, &hints, result);
  370. return (ret == 0);
  371. }
  372.  
  373. /**
  374. * 指定されたアドレス、サービスにバインドします。
  375. * 指定されたアドレスとサービスにより、複数候補がある場合は、
  376. * 最初に見つかったアドレスとポートにバインドします。
  377. *
  378. * @param sock 対象ソケット
  379. * @param addr アドレス
  380. * @param service サービス (例: "80", "http", "ssh" など)
  381. * @return true/false (bind 成功/失敗)
  382. */
  383. static bool KcSocket_bind(KcSocket *sock, const char *addr, const char *service)
  384. {
  385. struct addrinfo *bind_addr;
  386. bool is_success = sock->get_addrinfo(sock, &bind_addr, addr, service, true);
  387. if (is_success)
  388. {
  389. is_success = KcSocket_addrinfo_bind_and_connect(sock, bind_addr, NULL);
  390. freeaddrinfo(bind_addr);
  391. }
  392. return is_success;
  393. }
  394.  
  395. /**
  396. * ソケットを接続待ちソケットとしてマークをつけます。
  397. * 保留中の接続のキュー最大長を指定します。
  398. *
  399. * @param sock 対象ソケット
  400. * @param backlog バックログ
  401. * @return true/false (成功/失敗)
  402. */
  403. static bool KcSocket_listen(KcSocket *sock, int backlog)
  404. {
  405. bool result = false;
  406. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  407. if (info->sock_fd != INVALID_SOCKET)
  408. {
  409. int ret = listen(info->sock_fd, backlog);
  410. result = (ret != SOCKET_ERROR);
  411. }
  412. return result;
  413. }
  414.  
  415. /**
  416. * ソケットへの接続を受け付けます。
  417. *
  418. * @param sock 対象ソケット
  419. * @return 受け付けたソケット(失敗時NULL)
  420. */
  421. static KcSocket *KcSocket_accept(KcSocket *sock)
  422. {
  423. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  424. KcSocket *client = NULL;
  425. if (info->sock_fd != INVALID_SOCKET)
  426. {
  427. client = KcSocket_new(info->sock_type, info->sock_family);
  428. if (client != NULL)
  429. {
  430. KcSocketInfo *cinfo = (KcSocketInfo *)client->_info;
  431. cinfo->remote_addrlen = sizeof(struct sockaddr_storage);
  432. cinfo->sock_fd = accept(info->sock_fd, (struct sockaddr *)&cinfo->remote_addr, &cinfo->remote_addrlen);
  433. if (cinfo->sock_fd != INVALID_SOCKET)
  434. {
  435. memcpy(&cinfo->local_addr, &info->local_addr, info->local_addrlen);
  436. cinfo->local_addrlen = info->local_addrlen;
  437. cinfo->sock_type = SOCK_STREAM;
  438. cinfo->sock_family = cinfo->remote_addr.ss_family;
  439. }
  440. else
  441. {
  442. KcSocket_delete(client);
  443. client = NULL;
  444. }
  445. }
  446. }
  447. return client;
  448. }
  449.  
  450. /**
  451. * 指定されたアドレス、サービス接続します。
  452. * local_addr に NULL を指定した場合、自動的にローカルのアドレス、サービスが設定されます。
  453. *
  454. * @param sock 対象ソケット
  455. * @param addr アドレス
  456. * @param service サービス
  457. * @param local_addr ローカルアドレス
  458. * @param local_service ローカルサービス
  459. * @return true/false (成功/失敗)
  460. */
  461. static bool KcSocket_connect(
  462. KcSocket *sock, const char *addr, const char *service,
  463. const char *local_addr, const char *local_service)
  464. {
  465. // 接続先アドレス情報取得
  466. struct addrinfo *conn_addr = NULL;
  467. if (!sock->get_addrinfo(sock, &conn_addr, addr, service, false))
  468. {
  469. return false;
  470. }
  471.  
  472. // バインドアドレス情報取得
  473. bool is_success = false;
  474. struct addrinfo *bind_addr = NULL;
  475. if (local_addr != NULL)
  476. { // bind が必要
  477. is_success = sock->get_addrinfo(sock, &bind_addr, local_addr, local_service, true);
  478. if (is_success)
  479. {
  480. is_success = KcSocket_addrinfo_bind_and_connect(sock, bind_addr, conn_addr);
  481. freeaddrinfo(bind_addr);
  482. }
  483. }
  484. else
  485. {
  486. is_success = KcSocket_addrinfo_connect(sock, conn_addr, INVALID_SOCKET);
  487. }
  488. freeaddrinfo(conn_addr);
  489. return is_success;
  490. }
  491.  
  492. /**
  493. * ソケットをクローズします。
  494. *
  495. * @param sock 対象ソケット
  496. * @return true/false (成功/失敗)
  497. */
  498. static bool KcSocket_close(KcSocket *sock)
  499. {
  500. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  501. if (info->sock_type == SOCK_STREAM)
  502. { // TCP の場合は、出力を閉じて、届いているデータを読み取ってから close する。
  503. int ret = shutdown(info->sock_fd, SHUT_WR);
  504. if (ret == 0)
  505. {
  506. int read_size;
  507. char buff[1024];
  508. do
  509. { // 届いているデータを全て読み取る
  510. read_size = recv(info->sock_fd, buff, sizeof(buff), 0);
  511. } while (read_size > 0);
  512. }
  513. }
  514. sockclose(info->sock_fd);
  515. return true;
  516. }
  517.  
  518. /**
  519. * メッセージを送信します。
  520. *
  521. * @param sock 対象ソケット
  522. * @param buff メッセージ
  523. * @param size サイズ
  524. * @param flags フラグ (MSG_CONFIRM/MSG_DONTROUTE/MSG_DONTWAIT/MSG_EOR/MSG_MORE/MSG_NOSIGNAL/MSG_OOB)
  525. * @return 送信されたデータサイズ
  526. */
  527. static ssize_t KcSocket_send(KcSocket *sock, const char *buff, size_t size, int flags)
  528. {
  529. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  530. ssize_t write_size = 0;
  531. do
  532. {
  533. errno = 0;
  534. write_size = send(info->sock_fd, buff, size, flags);
  535. } while ((write_size < 0) && (errno == EINTR));
  536. return write_size;
  537. }
  538.  
  539. /**
  540. * メッセージを受信します。
  541. * 受信したメッセージは指定されたバッファに格納されます。
  542. *
  543. * @param sock 対象ソケット
  544. * @param buff メッセージ受信用バッファ
  545. * @param size バッファサイズ
  546. * @param flags フラグ (MSG_CONFIRM/MSG_DONTROUTE/MSG_DONTWAIT/MSG_EOR/MSG_MORE/MSG_NOSIGNAL/MSG_OOB)
  547. * @return 読み取ったデータサイズ
  548. */
  549. static ssize_t KcSocket_recv(KcSocket *sock, char *buff, size_t size, int flags)
  550. {
  551. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  552. ssize_t read_size;
  553. do
  554. {
  555. errno = 0;
  556. read_size = recv(info->sock_fd, buff, size, flags);
  557. } while ((read_size < 0) && (errno == EINTR));
  558. return read_size;
  559. }
  560.  
  561. /**
  562. * 指定されたアドレス、サービスにメッセージを送信します。
  563. *
  564. * @param sock 対象ソケット
  565. * @param buff メッセージ
  566. * @param size サイズ
  567. * @param flags フラグ (MSG_CONFIRM/MSG_DONTROUTE/MSG_DONTWAIT/MSG_EOR/MSG_MORE/MSG_NOSIGNAL/MSG_OOB)
  568. * @param addr アドレス
  569. * @param service サービス
  570. * @return 送信メッセージサイズ、エラー発生時は -1
  571. */
  572. static ssize_t KcSocket_sendto(
  573. KcSocket *sock, const char *buff, size_t size, int flags,
  574. const char *addr, const char *service)
  575. {
  576. // 接続先アドレス情報取得
  577. struct addrinfo *conn_addr = NULL;
  578. if (!sock->get_addrinfo(sock, &conn_addr, addr, service, false))
  579. { // 接続先情報取得NG
  580. return SOCKET_ERROR;
  581. }
  582.  
  583. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  584. socket_t tmp_sock = info->sock_fd;
  585. ssize_t send_size = SOCKET_ERROR;
  586. for (struct addrinfo *rp = conn_addr; rp != NULL; rp = rp->ai_next)
  587. {
  588. if (info->sock_fd == INVALID_SOCKET)
  589. { // sockfd が無効の場合、ソケットを生成する。
  590. tmp_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  591. if (tmp_sock == INVALID_SOCKET)
  592. {
  593. continue;
  594. }
  595. }
  596.  
  597. // マルチキャスト用 ifname が指定されている場合は設定する。
  598. KcSocket_set_mcastif(tmp_sock, rp->ai_family, info->mcast_v4_ifname, info->mcast_v6_ifname);
  599.  
  600. send_size = sendto(tmp_sock, buff, size, flags, rp->ai_addr, rp->ai_addrlen);
  601. if (send_size != SOCKET_ERROR)
  602. { // 送信成功
  603. info->sock_fd = tmp_sock;
  604. info->sock_family = rp->ai_family;
  605. info->remote_addrlen = rp->ai_addrlen;
  606. memcpy(&info->remote_addr, rp->ai_addr, rp->ai_addrlen);
  607. break;
  608. }
  609. else
  610. { // 送信失敗のため、一時的に生成したソケットをクローズする。
  611. sockclose(tmp_sock);
  612. }
  613. }
  614. freeaddrinfo(conn_addr);
  615. return send_size;
  616. }
  617.  
  618. /**
  619. * メッセージを受信します。
  620. * src_addr, src_service がいずれも NULL 出ない場合、
  621. * 送信元のアドレスとサービスが格納されます。
  622. *
  623. * @param sock 対象ソケット
  624. * @param buff メッセージ受信用バッファ
  625. * @param size バッファサイズ
  626. * @param flags フラグ (MSG_CONFIRM/MSG_DONTROUTE/MSG_DONTWAIT/MSG_EOR/MSG_MORE/MSG_NOSIGNAL/MSG_OOB)
  627. * @param src_addr 送信元アドレス格納用バッファ
  628. * @param src_addrlen 送信元アドレス格納用バッファサイズ
  629. * @param src_service 送信元サービス格納用バッファ
  630. * @param src_servicelen 送信元サービス格納用バッファサイズ
  631. * @return 受信メッセージサイズ、エラー発生時は -1
  632. */
  633. static ssize_t KcSocket_recvfrom(
  634. KcSocket *sock,
  635. char *buff, size_t size, int flags,
  636. char *src_addr, size_t src_addrlen,
  637. char *src_service, size_t src_servicelen)
  638. {
  639. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  640. ssize_t recv_size = SOCKET_ERROR;
  641. if (info->sock_fd != INVALID_SOCKET)
  642. {
  643. struct sockaddr_storage src_sockaddr;
  644. socklen_t src_sockaddrlen = sizeof(struct sockaddr_storage);
  645. recv_size = recvfrom(
  646. info->sock_fd, buff, size, flags, (struct sockaddr *)&src_sockaddr, &src_sockaddrlen);
  647.  
  648. if ((src_addr != NULL) && (src_service != NULL))
  649. {
  650. int ret = getnameinfo(
  651. (struct sockaddr *)&src_sockaddr, src_addrlen,
  652. src_addr, src_addrlen, src_service, src_servicelen,
  653. (NI_NUMERICHOST | NI_NUMERICSERV));
  654. if (ret != 0)
  655. {
  656. src_addr[0] = '\0';
  657. src_service[0] = '\0';
  658. }
  659. }
  660. }
  661. return recv_size;
  662. }
  663.  
  664. /**
  665. * TTL を設定します。
  666. *
  667. * @param sock 対象ソケット
  668. * @param val 設定する TTL
  669. * @return true/false (成功/失敗)
  670. */
  671. static bool KcSocket_set_ttl(KcSocket *sock, int val)
  672. {
  673. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  674. int ret = SOCKET_ERROR;
  675. switch (info->sock_family)
  676. {
  677. case AF_INET:
  678. {
  679. unsigned char ttl;
  680. ttl = (unsigned char)val;
  681. ret = setsockopt(info->sock_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
  682. }
  683. break;
  684. case AF_INET6:
  685. {
  686. int hop;
  687. hop = val;
  688. ret = setsockopt(info->sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hop, sizeof(hop));
  689. }
  690. break;
  691. default:
  692. // unspoorted socket family
  693. break;
  694. }
  695. return (ret == 0);
  696. }
  697.  
  698. /**
  699. * マルチキャストグループに参加するために JOIN します。
  700. * IPv4 の場合、ifname に、IPアドレスを指定ください。
  701. * IPv6 の場合、ifname にインタフェース名 (例: eth0 など)を指定ください。
  702. * ifname に NULL が指定された場合、任意のインタフェースとなります。
  703. *
  704. * @param sock 対象ソケット
  705. * @param addr マルチキャストアドレス
  706. * @param ifname インタフェース名
  707. * @return true/false (成功/失敗)
  708. */
  709. static bool KcSocket_join(KcSocket *sock, const char *addr, const char *ifname)
  710. {
  711. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  712. int ret = SOCKET_ERROR;
  713. switch (info->sock_family)
  714. {
  715. case AF_INET:
  716. ret = KcSocket_join_ipv4(sock, addr, ifname);
  717. break;
  718. case AF_INET6:
  719. ret = KcSocket_join_ipv6(sock, addr, ifname);
  720. break;
  721. default:
  722. // NOP
  723. break;
  724. }
  725. return (ret == 0);
  726. }
  727.  
  728. /**
  729. * マルチキャストグループから離脱します。
  730. *
  731. * @param sock 対象ソケット
  732. * @param addr マルチキャストアドレス
  733. * @param ifname インタフェース名
  734. * @return true/false (成功/失敗)
  735. */
  736. static bool KcSocket_leave(KcSocket *sock, const char *addr, const char *ifname)
  737. {
  738. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  739. int ret = SOCKET_ERROR;
  740. switch (info->sock_family)
  741. {
  742. case AF_INET:
  743. ret = KcSocket_leave_ipv4(sock, addr, ifname);
  744. break;
  745. case AF_INET6:
  746. ret = KcSocket_leave_ipv6(sock, addr, ifname);
  747. break;
  748. default:
  749. // NOP
  750. break;
  751. }
  752. return (ret == 0);
  753. }
  754.  
  755. /**
  756. * マルチキャストを送信するインタフェースを指定します。
  757. *
  758. * @param sock 対象ソケット
  759. * @param v4_ifname インタフェース名(IPアドレス)
  760. * @param v6_ifname インタフェース名(eth0 など)
  761. * @return true/false (成功/失敗)
  762. */
  763. static void KcSocket_set_ifname(KcSocket *sock, const char *v4_ifname, const char *v6_ifname)
  764. {
  765. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  766. info->mcast_v4_ifname = v4_ifname;
  767. info->mcast_v6_ifname = v6_ifname;
  768. printf("v4 %s\n", info->mcast_v4_ifname);
  769. printf("v6 %s\n", info->mcast_v6_ifname);
  770. }
  771.  
  772. /**
  773. * 指定されたソケットの情報を指定されたバッファに出力します。
  774. *
  775. * @param sock 対象ソケット
  776. * @param buff バッファ
  777. * @param size バッファのサイズ
  778. */
  779. static void KcSocket_print_info(KcSocket *sock, char *buff, size_t size)
  780. {
  781. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  782.  
  783. char *write_ptr = buff;
  784. char *end_ptr = &buff[size];
  785. write_ptr += snprintf(write_ptr, (end_ptr - write_ptr), "local : ");
  786. write_ptr += KcSocket_print_addr(write_ptr, (end_ptr - write_ptr), (struct sockaddr *)&info->local_addr, info->local_addrlen);
  787. write_ptr += snprintf(write_ptr, (end_ptr - write_ptr), "\n");
  788. write_ptr += snprintf(write_ptr, (end_ptr - write_ptr), "remote: ");
  789. write_ptr += KcSocket_print_addr(write_ptr, (end_ptr - write_ptr), (struct sockaddr *)&info->remote_addr, info->remote_addrlen);
  790. write_ptr += snprintf(write_ptr, (end_ptr - write_ptr), "\n");
  791. UNUSED_VARIABLE(write_ptr);
  792. }
  793.  
  794. ////////////////////////////////////////////////////////////////////////////////
  795. //
  796. // [内部関数]
  797. //
  798.  
  799. /**
  800. * 指定された接続アドレス情報をもとにソケットの生成、接続を試みます。
  801. * 接続済みソケット sockfd が有効な場合、sockfd を用いて接続します。
  802. *
  803. * @param sock 対象ソケット
  804. * @param conn_addrinfo 接続アドレス情報
  805. * @param sockfd 接続済みソケット
  806. * @return true/false (接続成功/失敗)
  807. */
  808. static bool KcSocket_addrinfo_connect(KcSocket *sock, struct addrinfo *conn_addrinfo, socket_t sockfd)
  809. {
  810. bool is_success = false;
  811. socket_t tmp_sock = sockfd;
  812. for (struct addrinfo *rp = conn_addrinfo; rp != NULL; rp = rp->ai_next)
  813. {
  814. if (sockfd == INVALID_SOCKET)
  815. { // sockfd が無効の場合、ソケットを生成する。
  816. tmp_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  817. if (tmp_sock == INVALID_SOCKET)
  818. {
  819. continue;
  820. }
  821. }
  822.  
  823. int ret = connect(tmp_sock, rp->ai_addr, rp->ai_addrlen);
  824. is_success = (ret != SOCKET_ERROR);
  825. if (is_success)
  826. {
  827. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  828. info->sock_fd = tmp_sock;
  829. info->sock_family = rp->ai_family;
  830. info->remote_addrlen = rp->ai_addrlen;
  831. memcpy(&info->remote_addr, rp->ai_addr, rp->ai_addrlen);
  832. break;
  833. }
  834.  
  835. if (sockfd == INVALID_SOCKET)
  836. { // sockfd が無効の場合、一時的に生成したソケットをクローズする。
  837. sockclose(tmp_sock);
  838. }
  839. }
  840. return is_success;
  841. }
  842.  
  843. /**
  844. * 指定された接続アドレス情報をもとにソケットの生成、バインドを試みます。
  845. * conn_addrinfo が NULL でない場合、バインド後に接続を試みます。
  846. *
  847. * @param sock 対象ソケット
  848. * @param bind_addrinfo バインドアドレス情報
  849. * @param conn_addrinfo 接続アドレス情報
  850. * @return true/false (接続成功/失敗)
  851. */
  852. static bool KcSocket_addrinfo_bind_and_connect(
  853. KcSocket *sock, struct addrinfo *bind_addrinfo, struct addrinfo *conn_addrinfo)
  854. {
  855. int ret;
  856. bool is_success = false;
  857.  
  858. for (struct addrinfo *rp = bind_addrinfo; rp != NULL; rp = rp->ai_next)
  859. { // sokcet : ソケット生成
  860. socket_t tmp_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  861. if (tmp_sock == INVALID_SOCKET)
  862. {
  863. continue;
  864. }
  865.  
  866. // bind
  867. const int on = 1;
  868. setsockopt(tmp_sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
  869. ret = bind(tmp_sock, rp->ai_addr, rp->ai_addrlen);
  870. is_success = (ret == 0);
  871. if (!is_success)
  872. { // bind 失敗したので次へ
  873. sockclose(tmp_sock);
  874. continue;
  875. }
  876.  
  877. // connect
  878. if (conn_addrinfo)
  879. {
  880. is_success = KcSocket_addrinfo_connect(sock, conn_addrinfo, tmp_sock);
  881. if (!is_success)
  882. { // connect 失敗したので次へ
  883. sockclose(tmp_sock);
  884. continue;
  885. }
  886. }
  887.  
  888. // bind または、bind と connect 成功
  889. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  890. info->sock_fd = tmp_sock;
  891. info->sock_family = rp->ai_family;
  892. info->local_addrlen = rp->ai_addrlen;
  893. memcpy(&info->local_addr, rp->ai_addr, rp->ai_addrlen);
  894. break;
  895. }
  896. return is_success;
  897. }
  898.  
  899. /**
  900. * マルチキャストグループに参加するために JOIN (IPv4)します。
  901. *
  902. * @param sock 対象ソケット
  903. * @param addr マルチキャストアドレス
  904. * @param ifname インタフェース名(IP)
  905. * @return 0/-1(成功/失敗)
  906. */
  907. static int KcSocket_join_ipv4(KcSocket *sock, const char *addr, const char *ifname)
  908. {
  909. struct ip_mreq mreq;
  910. mreq.imr_multiaddr.s_addr = inet_addr(addr);
  911. mreq.imr_interface.s_addr = (ifname != NULL) ? inet_addr(ifname) : htonl(INADDR_ANY);
  912.  
  913. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  914. int ret = setsockopt(info->sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
  915. return ret;
  916. }
  917.  
  918. /**
  919. * マルチキャストグループに参加するために JOIN (IPv6)します。
  920. *
  921. * @param sock 対象ソケット
  922. * @param addr マルチキャストアドレス
  923. * @param ifname インタフェース名
  924. * @return 0/-1 (成功/失敗)
  925. */
  926. static int KcSocket_join_ipv6(KcSocket *sock, const char *addr, const char *ifname)
  927. {
  928. struct ipv6_mreq mreq6;
  929. mreq6.ipv6mr_interface = (ifname != NULL) ? if_nametoindex(ifname) : 0;
  930. int ret = inet_pton(AF_INET6, addr, &mreq6.ipv6mr_multiaddr);
  931. if (ret != SOCKET_ERROR)
  932. {
  933. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  934. ret = setsockopt(info->sock_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
  935. }
  936. return ret;
  937. }
  938.  
  939. /**
  940. * マルチキャストグループから離脱します(IPv4)。
  941. *
  942. * @param sock 対象ソケット
  943. * @param addr マルチキャストアドレス
  944. * @param ifname インタフェース名(IP)
  945. * @return 0/-1 (成功/失敗)
  946. */
  947. static int KcSocket_leave_ipv4(KcSocket *sock, const char *addr, const char *ifname)
  948. {
  949. struct ip_mreq mreq;
  950. mreq.imr_multiaddr.s_addr = inet_addr(addr);
  951. mreq.imr_interface.s_addr = (ifname != NULL) ? inet_addr(ifname) : htonl(INADDR_ANY);
  952.  
  953. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  954. int ret = setsockopt(info->sock_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
  955. return ret;
  956. }
  957.  
  958. /**
  959. * マルチキャストグループに離脱します(IPv6)。
  960. *
  961. * @param sock 対象ソケット
  962. * @param addr マルチキャストアドレス
  963. * @param ifname インタフェース名
  964. * @return 0/-1 (成功/失敗)
  965. */
  966. static int KcSocket_leave_ipv6(KcSocket *sock, const char *addr, const char *ifname)
  967. {
  968. struct ipv6_mreq mreq6;
  969. mreq6.ipv6mr_interface = (ifname != NULL) ? if_nametoindex(ifname) : 0;
  970. int ret = inet_pton(AF_INET6, addr, &mreq6.ipv6mr_multiaddr);
  971. if (ret != SOCKET_ERROR)
  972. {
  973. KcSocketInfo *info = (KcSocketInfo *)sock->_info;
  974. ret = setsockopt(info->sock_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6));
  975. }
  976. return ret;
  977. }
  978.  
  979. /**
  980. * マルチキャストを送信するためのインタフェースを設定します。
  981. *
  982. * @param sock 対象ソケット
  983. * @return true/false (成功/失敗)
  984. */
  985. static bool KcSocket_set_mcastif(
  986. socket_t tmp_sock, int family,
  987. const char* mcast_v4_ifname, const char* mcast_v6_ifname)
  988. {
  989. int ret = SOCKET_ERROR;
  990. switch (family)
  991. {
  992. case AF_INET:
  993. ret = (mcast_v4_ifname)
  994. ? KcSocket_set_mcastif_ipv4(tmp_sock, mcast_v4_ifname)
  995. : 0;
  996. break;
  997. case AF_INET6:
  998. ret = (mcast_v6_ifname)
  999. ? KcSocket_set_mcastif_ipv6(tmp_sock, mcast_v6_ifname)
  1000. : 0;
  1001. break;
  1002. default:
  1003. // NOP
  1004. break;
  1005. }
  1006. return (ret == 0);
  1007. }
  1008.  
  1009. /**
  1010. * マルチキャストを送信するためのインタフェースを設定します(IPv4)。
  1011. *
  1012. * @param sock 対象一時ソケット
  1013. * @param ifname インタフェース名
  1014. * @return 0/-1 (成功/失敗)
  1015. */
  1016. static int KcSocket_set_mcastif_ipv4(socket_t tmp_sock, const char *ifname)
  1017. {
  1018. struct in_addr ifaddr;
  1019. ifaddr.s_addr = (ifname != NULL) ? inet_addr(ifname) : htonl(INADDR_ANY);
  1020. int ret = setsockopt(tmp_sock, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, sizeof(ifaddr));
  1021. return ret;
  1022. }
  1023.  
  1024. /**
  1025. * マルチキャストを送信するためのインタフェースを設定します(IPv6)。
  1026. *
  1027. * @param sock 対象一時ソケット
  1028. * @param ifname インタフェース名
  1029. * @return 0/-1 (成功/失敗)
  1030. */
  1031. static int KcSocket_set_mcastif_ipv6(socket_t tmp_sock, const char *ifname)
  1032. {
  1033. unsigned int ifindex = (ifname != NULL) ? if_nametoindex(ifname) : 0;
  1034. int ret = setsockopt(tmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
  1035. return ret;
  1036. }
  1037.  
  1038. /**
  1039. * 指定された addr の情報を出力します。
  1040. *
  1041. * @param buff バッファ
  1042. * @param size サイズ
  1043. * @param addr アドレス
  1044. * @param addrlen アドレス長
  1045. * @return バッファに書き出したバイト数
  1046. */
  1047. static int KcSocket_print_addr(char *buff, size_t size, const struct sockaddr *addr, size_t addrlen)
  1048. {
  1049. char tmp_addr[NI_MAXHOST];
  1050. char tmp_service[NI_MAXSERV];
  1051. int ret = getnameinfo(
  1052. addr, addrlen,
  1053. tmp_addr, sizeof(tmp_addr), tmp_service, sizeof(tmp_service), NI_NUMERICHOST | NI_NUMERICSERV);
  1054. int write_size = 0;
  1055. if (ret == 0)
  1056. {
  1057. write_size = snprintf(buff, size, "%s:%s", tmp_addr, tmp_service);
  1058. }
  1059. else
  1060. {
  1061. write_size = snprintf(buff, size, "-:-");
  1062. }
  1063. return write_size;
  1064. }