* Copyright (c) Huawei Technologies Co.,Ltd. 2024-2024 all rigths reserved.
*
* GR is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* gr_cli_conn.c
*
*
* IDENTIFICATION
* src/common_api/gr_cli_conn.c
*
* -------------------------------------------------------------------------
*/
#include "gr_cli_conn.h"
#include "gr_api_impl.h"
#include "gr_malloc.h"
#ifdef __cplusplus
extern "C" {
#endif
char g_gr_inst_path[CM_MAX_PATH_LEN] = {0};
typedef struct st_gr_conn_info {
latch_t conn_latch;
uint32_t conn_num;
bool32 isinit;
int32_t timeout;
} gr_conn_info_t;
static gr_conn_info_t g_gr_conn_info = {{0, 0, 0, 0, 0}, 0, CM_FALSE, 0};
void gr_conn_release(pointer_t thv_addr)
{
gr_conn_t *conn = (gr_conn_t *)thv_addr;
if (conn->pipe.link.uds.closed != CM_TRUE) {
gr_disconnect(conn);
cm_latch_x(&g_gr_conn_info.conn_latch, 1, NULL);
g_gr_conn_info.conn_num--;
if (g_gr_conn_info.conn_num == 0) {
gr_destroy();
}
cm_unlatch(&g_gr_conn_info.conn_latch, NULL);
}
GR_FREE_POINT(conn);
}
void gr_conn_opts_release(pointer_t thv_addr)
{
GR_FREE_POINT(thv_addr);
}
static thv_ctrl_t g_gr_thv_ctrls[] = {
{NULL, gr_conn_create, gr_conn_release},
{NULL, gr_conn_opts_create, gr_conn_opts_release},
};
void gr_clt_env_init(void)
{
if (g_gr_conn_info.isinit == CM_FALSE) {
cm_latch_x(&g_gr_conn_info.conn_latch, 1, NULL);
if (g_gr_conn_info.isinit == CM_FALSE) {
status_t status = cm_launch_thv(g_gr_thv_ctrls, sizeof(g_gr_thv_ctrls) / sizeof(g_gr_thv_ctrls[0]));
if (status != CM_SUCCESS) {
LOG_RUN_ERR("gr client initialization failed.");
cm_unlatch(&g_gr_conn_info.conn_latch, NULL);
return;
}
g_gr_conn_info.isinit = CM_TRUE;
}
cm_unlatch(&g_gr_conn_info.conn_latch, NULL);
}
}
status_t gr_try_conn(gr_conn_opt_t *options, gr_conn_t *conn, const char *addr)
{
status_t status = CM_ERROR;
cm_latch_x(&g_gr_conn_info.conn_latch, 1, NULL);
do {
gr_free_packet_buffer(&conn->pack);
status = gr_connect(addr, options, conn);
GR_BREAK_IFERR2(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "gr client connet server failed."));
uint32_t max_open_file = GR_MAX_OPEN_FILES;
conn->proto_version = GR_PROTO_VERSION;
status = gr_cli_handshake(conn, max_open_file);
GR_BREAK_IFERR3(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "gr client handshake to server failed."),
gr_disconnect(conn));
status = gr_cli_ssl_connect(conn);
GR_BREAK_IFERR2(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "gr client ssl connet server failed."));
g_gr_conn_info.conn_num++;
} while (0);
cm_unlatch(&g_gr_conn_info.conn_latch, NULL);
return status;
}
status_t gr_conn_opts_create(pointer_t *result, const char *addr)
{
gr_conn_opt_t *options = (gr_conn_opt_t *)cm_malloc(sizeof(gr_conn_opt_t));
if (options == NULL) {
GR_THROW_ERROR(ERR_GR_ALLOC_MEMORY, sizeof(gr_conn_opt_t), "gr_conn_opts_create");
return CM_ERROR;
}
(void)memset_s(options, sizeof(gr_conn_opt_t), 0, sizeof(gr_conn_opt_t));
*result = options;
return CM_SUCCESS;
}
static status_t gr_conn_sync(gr_conn_opt_t *options, gr_conn_t *conn, const char *addr)
{
status_t ret = CM_ERROR;
int timeout = (options != NULL ? options->timeout : g_gr_tcp_conn_timeout);
do {
ret = gr_try_conn(options, conn, addr);
if (ret == CM_SUCCESS) {
break;
}
if (cm_get_os_error() == ENOENT) {
break;
}
} while (timeout == GR_CONN_NEVER_TIMEOUT);
return ret;
}
status_t gr_conn_create(pointer_t *result, const char *addr)
{
gr_conn_t *conn = (gr_conn_t *)cm_malloc(sizeof(gr_conn_t));
if (conn == NULL) {
GR_THROW_ERROR(ERR_GR_ALLOC_MEMORY, sizeof(gr_conn_t), "gr_conn_create");
return CM_ERROR;
}
(void)memset_s(conn, sizeof(gr_conn_t), 0, sizeof(gr_conn_t));
gr_init_packet(&conn->pack, conn->pipe.options);
gr_conn_opt_t *options = NULL;
(void)cm_get_thv(GLOBAL_THV_OBJ1, CM_FALSE, (pointer_t *)&options, addr);
if (gr_conn_sync(options, conn, addr) != CM_SUCCESS) {
GR_THROW_ERROR(ERR_GR_CONNECT_FAILED, cm_get_os_error(), strerror(cm_get_os_error()));
GR_FREE_POINT(conn);
return CM_ERROR;
}
#ifdef ENABLE_GRTEST
conn->conn_pid = getpid();
#endif
*result = conn;
return CM_SUCCESS;
}
static status_t gr_get_conn(gr_conn_t **conn, const char *addr)
{
cm_reset_error();
gr_clt_env_init();
if (cm_get_thv(GLOBAL_THV_OBJ0, CM_TRUE, (pointer_t *)conn, addr) != CM_SUCCESS) {
LOG_RUN_ERR("[GR API] connection failed, reason: %s", strerror(cm_get_os_error()));
GR_THROW_ERROR(ERR_GR_CONNECT_FAILED, cm_get_os_error(), strerror(cm_get_os_error()));
return CM_ERROR;
}
if ((*conn)->pipe.link.uds.closed) {
LOG_RUN_ERR("[GR API] connection is closed");
GR_THROW_ERROR(ERR_GR_CONNECTION_CLOSED);
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t gr_enter_api(gr_conn_t **conn, const char *addr)
{
status_t status = gr_get_conn(conn, addr);
if (status != CM_SUCCESS) {
return status;
}
return CM_SUCCESS;
}
status_t check_server_addr_format(const char *server_addr)
{
if (server_addr == NULL) {
LOG_RUN_ERR("[GR API] ERROR INFO : server address is NULL.");
return GR_ERROR;
}
size_t addr_len = strlen(server_addr);
if (addr_len == 0 || addr_len >= CM_MAX_IP_LEN) {
LOG_RUN_ERR("[GR API] ERROR INFO : invalid server address length: %zu.", addr_len);
return GR_ERROR;
}
const char *port_sep = strrchr(server_addr, ':');
if (port_sep == NULL) {
LOG_RUN_ERR("[GR API] ERROR INFO : server address(%s) format error: missing port", server_addr);
return GR_ERROR;
}
size_t ip_len = port_sep - server_addr;
if (ip_len == 0 || ip_len >= CM_MAX_IP_LEN) {
LOG_RUN_ERR("[GR API] ERROR INFO : invalid IP length in server address(%s)", server_addr);
return GR_ERROR;
}
const char *port_str = port_sep + 1;
if (*port_str == '\0') {
LOG_RUN_ERR("[GR API] ERROR INFO : server address(%s) format error: empty port", server_addr);
return GR_ERROR;
}
char *end_ptr = NULL;
long port = strtol(port_str, &end_ptr, 10);
if (*end_ptr != '\0' || port <= 0 || port > 65535) {
LOG_RUN_ERR("[GR API] ERROR INFO : invalid port number in server address(%s)", server_addr);
return GR_ERROR;
}
char ip_buf[CM_MAX_IP_LEN] = {0};
errno_t rc = strncpy_s(ip_buf, CM_MAX_IP_LEN, server_addr, ip_len);
if (rc != EOK) {
LOG_RUN_ERR("[GR API] ERROR INFO : failed to copy IP address");
return GR_ERROR;
}
struct in_addr addr;
if (inet_pton(AF_INET, ip_buf, &addr) != 1) {
LOG_RUN_ERR("[GR API] ERROR INFO : invalid IP format in server address(%s)", server_addr);
return GR_ERROR;
}
return GR_SUCCESS;
}
#ifdef __cplusplus
}
#endif