#include <stdio.h> #include <errno.h> #include <kc.h> #include <kc_ut.h> #include <kc_assert.h> #include <kc_memory.h> #include <kc_threads.h> #include <kc_socket.h> #include "ut.h" // プロトタイプ宣言 static void test_socket_new(void); static void test_socket_dgram1(void); static void test_socket_stream1(void); static void test_socket_stream2(void); static void test_socket_mcast1_ipv4(void); // テスト用変数 /** * KcSocket 単体テストスイート */ void suite_socket(void) { KcUt *ut = KcUt_get_instance(); ut->add(ut, UT_TESTCASE, "socket new/delete", test_socket_new); ut->add(ut, UT_TESTCASE, "socket dgram1", test_socket_dgram1); ut->add(ut, UT_TESTCASE, "socket stream1", test_socket_stream1); ut->add(ut, UT_TESTCASE, "socket stream2", test_socket_stream2); ut->add(ut, UT_TESTCASE, "socket mcast1", test_socket_mcast1_ipv4); } typedef struct { int type; int family; const char *addr; const char *service; const char *mcast_addr; const char *mcast_iface; int exp_recv_size; const char *exp_recv_data; const char *exp_src_addr; const char *exp_src_service; } TestSocketInfo; static int test_socket_thread_echo_server(void *arg) { TestSocketInfo *info = (TestSocketInfo *)arg; KcSocket *server = KcSocket_new(info->type, info->family); assert_not_null(server); bool ret = server->bind(server, info->addr, info->service); assert_true(ret); // マルチキャスト if (info->mcast_addr != NULL) { server->join(server, info->mcast_addr, info->mcast_iface); } char recv_buff[16] = {'\0'}; char src_addr[NI_MAXHOST]; char src_service[NI_MAXSERV]; // メッセージ受信 int recv_size; KcSocket *connected_socket = NULL; if (info->type == SOCK_STREAM) { // TCP ret = server->listen(server, 1); assert_true(ret); connected_socket = server->accept(server); assert_not_null(connected_socket); const char *raddr = connected_socket->get_remote_addr(connected_socket); assert_not_null(raddr); snprintf(src_addr, NI_MAXHOST, "%s", raddr); int rport = connected_socket->get_remote_port(connected_socket); assert_true(rport != 0); snprintf(src_service, NI_MAXSERV, "%d", rport); recv_size = connected_socket->recv(connected_socket, recv_buff, sizeof(recv_buff), 0); } else { // UDP recv_size = server->recvfrom( server, recv_buff, sizeof(recv_buff), 0, src_addr, NI_MAXHOST, src_service, NI_MAXSERV); printf("recv [%s] (size=%d)\n", recv_buff, recv_size); } assert_equals(info->exp_recv_size, recv_size); assert_equals(info->exp_recv_data, recv_buff); if (info->exp_src_addr) { assert_equals(info->exp_src_addr, src_addr); } if (info->exp_src_service) { assert_equals(info->exp_src_service, src_service); } // 応答送信 int write_size; if (info->type == SOCK_STREAM) { // TCP write_size = connected_socket->send(connected_socket, recv_buff, recv_size, 0); ret = connected_socket->close(connected_socket); assert_true(ret); KcSocket_delete(connected_socket); } else { // UDP printf("sendto: %s:%s\n", src_addr, src_service); printf(" data: %s (size=%d)\n", recv_buff, recv_size); write_size = server->sendto(server, recv_buff, recv_size, 0, src_addr, src_service); if (info->mcast_addr != NULL) { server->leave(server, info->mcast_addr, info->mcast_iface); } } assert_equals(info->exp_recv_size, write_size); KcSocket_delete(server); return 0; } /** * Socket 生成/破棄。 * * @process KcSocket_new を実行する。。 * @result KcSocket が生成されること。 * * @process KcSocket_delete にて Socket を破棄する。 * @result Socket が破棄されること。 */ static void test_socket_new(void) { // 受信側 KcThread *server = KcThread_new(test_socket_thread_echo_server); TestSocketInfo info = { .type = SOCK_DGRAM, .family = AF_UNSPEC, .addr = "127.0.0.1", .service = "5000", .mcast_addr = NULL, .mcast_iface = NULL, .exp_recv_size = 4, .exp_recv_data = "ABC", .exp_src_addr = NULL, .exp_src_service = NULL}; server->start(server, &info); KcThread_msleep(100, false); // 送信側 KcSocket *client = KcSocket_new(SOCK_DGRAM, AF_UNSPEC); assert_not_null(client); // メッセージ送信 int send_size = client->sendto(client, info.exp_recv_data, info.exp_recv_size, 0, info.addr, info.service); assert_equals(info.exp_recv_size, send_size); // ソケット取得 socket_t sock = client->get_socket(client); assert_true(sock != INVALID_SOCKET); // タイプ確認 int type = client->get_type(client); assert_equals(SOCK_DGRAM, type); // ファミリー確認 (IPv4 [AF_INET]) int family = client->get_family(client); assert_equals(AF_INET, family); // 応答受信 char buff[16]; int recv_size = client->recvfrom(client, buff, sizeof(buff), 0, NULL, 0, NULL, 0); assert_equals(info.exp_recv_size, recv_size); assert_equals(info.exp_recv_data, buff); bool ret = client->close(client); assert_true(ret); KcSocket_delete(client); server->join(server); KcThread_delete(server); } /** * UDP 送受信 */ static void test_socket_dgram1(void) { // 受信側 KcThread *server = KcThread_new(test_socket_thread_echo_server); TestSocketInfo info = { .type = SOCK_DGRAM, .family = AF_UNSPEC, .addr = "127.0.0.1", .service = "5000", .mcast_addr = NULL, .mcast_iface = NULL, .exp_recv_size = 5, .exp_recv_data = "DEFG", .exp_src_addr = "127.0.0.1", .exp_src_service = "6000"}; server->start(server, &info); KcThread_msleep(100, false); // 送信側 KcSocket *client = KcSocket_new(SOCK_DGRAM, AF_UNSPEC); assert_not_null(client); bool can_bind = client->bind(client, info.exp_src_addr, info.exp_src_service); assert_true(can_bind); const char *local_addr = client->get_local_addr(client); assert_equals(info.exp_src_addr, local_addr); int port = client->get_local_port(client); assert_equals(atoi(info.exp_src_service), port); char buff[1024]; client->print_info(client, buff, sizeof(buff)); assert_equals("local : 127.0.0.1:6000\nremote: -:-\n", buff); int send_size = client->sendto(client, info.exp_recv_data, info.exp_recv_size, 0, info.addr, info.service); assert_equals(info.exp_recv_size, send_size); // ソケット取得 socket_t sock = client->get_socket(client); assert_true(sock != INVALID_SOCKET); // タイプ確認 int type = client->get_type(client); assert_equals(SOCK_DGRAM, type); // ファミリー確認 (IPv4 [AF_INET]) int family = client->get_family(client); assert_equals(AF_INET, family); // 応答受信 int recv_size = client->recvfrom(client, buff, sizeof(buff), 0, NULL, 0, NULL, 0); assert_equals(info.exp_recv_size, recv_size); assert_equals(info.exp_recv_data, buff); bool ret = client->close(client); assert_true(ret); KcSocket_delete(client); server->join(server); KcThread_delete(server); } /** * TCP 送受信 */ static void test_socket_stream1(void) { // 受信側 KcThread *server = KcThread_new(test_socket_thread_echo_server); TestSocketInfo info = { .type = SOCK_STREAM, .family = AF_UNSPEC, .addr = "127.0.0.1", .service = "5000", .mcast_addr = NULL, .mcast_iface = NULL, .exp_recv_size = 4, .exp_recv_data = "XYZ", .exp_src_addr = NULL, .exp_src_service = NULL}; server->start(server, &info); KcThread_msleep(100, false); // 送信側 KcSocket *client = KcSocket_new(SOCK_STREAM, AF_UNSPEC); assert_not_null(client); bool ret = client->connect(client, info.addr, info.service, NULL, NULL); assert_true(ret); // ソケット取得 socket_t sock = client->get_socket(client); assert_true(sock != INVALID_SOCKET); // タイプ確認 int type = client->get_type(client); assert_equals(SOCK_STREAM, type); // ファミリー確認 (IPv4 [AF_INET]) int family = client->get_family(client); assert_equals(AF_INET, family); int send_size = client->send(client, info.exp_recv_data, info.exp_recv_size, 0); assert_equals(4, send_size); // 応答受信 char buff[16]; int recv_size = client->recv(client, buff, sizeof(buff), 0); assert_equals(info.exp_recv_size, recv_size); ret = client->close(client); assert_true(ret); KcSocket_delete(client); server->join(server); KcThread_delete(server); } /** * TCP 送受信 */ static void test_socket_stream2(void) { // 受信側 KcThread *server = KcThread_new(test_socket_thread_echo_server); TestSocketInfo info = { .type = SOCK_STREAM, .family = AF_UNSPEC, .addr = "127.0.0.1", .service = "5000", .mcast_addr = NULL, .mcast_iface = NULL, .exp_recv_size = 4, .exp_recv_data = "XYZ", .exp_src_addr = "127.0.0.1", .exp_src_service = "6000"}; server->start(server, &info); KcThread_msleep(100, false); // 送信側 KcSocket *client = KcSocket_new(SOCK_STREAM, AF_UNSPEC); assert_not_null(client); bool ret = client->connect(client, info.addr, info.service, info.exp_src_addr, info.exp_src_service); assert_true(ret); // ソケット取得 socket_t sock = client->get_socket(client); assert_true(sock != INVALID_SOCKET); // タイプ確認 int type = client->get_type(client); assert_equals(SOCK_STREAM, type); // ファミリー確認 (IPv4 [AF_INET]) int family = client->get_family(client); assert_equals(AF_INET, family); const char *local_addr = client->get_local_addr(client); assert_equals(info.exp_src_addr, local_addr); int port = client->get_local_port(client); assert_equals(atoi(info.exp_src_service), port); char buff[1024]; client->print_info(client, buff, sizeof(buff)); assert_equals("local : 127.0.0.1:6000\nremote: 127.0.0.1:5000\n", buff); int send_size = client->send(client, info.exp_recv_data, info.exp_recv_size, 0); assert_equals(4, send_size); // 応答受信 int recv_size = client->recv(client, buff, sizeof(buff), 0); assert_equals(info.exp_recv_size, recv_size); printf("buff=%s\n", buff); ret = client->close(client); assert_true(ret); KcSocket_delete(client); server->join(server); KcThread_delete(server); } /** * マルチキャスト送受信 */ static void test_socket_mcast1_ipv4(void) { // 受信側 KcThread *server = KcThread_new(test_socket_thread_echo_server); TestSocketInfo info = { .type = SOCK_DGRAM, .family = AF_UNSPEC, .addr = "0.0.0.0", .service = "5000", .mcast_addr = "224.0.0.10", .mcast_iface = NULL, .exp_recv_size = 6, .exp_recv_data = "AAAAA", .exp_src_addr = NULL, .exp_src_service = NULL}; server->start(server, &info); KcThread_msleep(100, false); // 送信側 KcSocket *client = KcSocket_new(SOCK_DGRAM, AF_UNSPEC); assert_not_null(client); client->set_ifname(client, "10.0.2.15", NULL); int send_size = client->sendto(client, info.exp_recv_data, info.exp_recv_size, 0, info.mcast_addr, info.service); assert_equals(info.exp_recv_size, send_size); // ソケット取得 socket_t sock = client->get_socket(client); assert_true(sock != INVALID_SOCKET); // タイプ確認 int type = client->get_type(client); assert_equals(SOCK_DGRAM, type); // ファミリー確認 (IPv4 [AF_INET]) int family = client->get_family(client); assert_equals(AF_INET, family); // 応答受信 char buff[16]; int recv_size = client->recvfrom(client, buff, sizeof(buff), 0, NULL, 0, NULL, 0); assert_equals(info.exp_recv_size, recv_size); assert_equals((char *)info.exp_recv_data, buff); bool ret = client->close(client); assert_true(ret); KcSocket_delete(client); server->join(server); KcThread_delete(server); }