* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* 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 FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include "ascend_hal.h"
#include "hdc_cmn.h"
#include "stddef.h"
#include "securec.h"
#include "hdc_ppc.h"
#include "hdc_adapt.h"
#if defined (CFG_PLATFORM_EQUIP) && defined (CFG_SOC_PLATFORM_RC)
#define DRV_HDC_RC_USER_NUM 4
#define DRV_HDC_RC_USER_NAME_LEN 20
static struct {
char user_name[DRV_HDC_RC_USER_NAME_LEN];
} hdc_rc_user_name_list[DRV_HDC_RC_USER_NUM] = {
{"root"},
{"HwHiAiUser"},
{"HwDmUser"},
{"HwBaseUser"},
};
STATIC bool drv_hdc_ppc_check_user(struct passwd *user)
{
int i;
for (i = 0; i < DRV_HDC_RC_USER_NUM; i++) {
if (strcmp(user->pw_name, hdc_rc_user_name_list[i].user_name) == 0) {
return true;
}
}
return false;
}
#endif
STATIC void drv_hdc_socket_create_dir(void)
{
#ifdef CFG_SOC_PLATFORM_RC
int ret;
struct passwd *user = NULL;
user = getpwuid(getuid());
if (user == NULL) {
HDC_LOG_ERR("Failed to get the current user.\n");
return;
}
if (strcmp(user->pw_name, "root") == 0) {
ret = sprintf_s(g_ppc_dirs, sizeof(g_ppc_dirs), "%s%s%s", "/", user->pw_name, "/hdc_ppc/");
} else {
ret = sprintf_s(g_ppc_dirs, sizeof(g_ppc_dirs), "%s%s%s", "/home/", user->pw_name, "/hdc_ppc/");
}
if (ret < 0) {
HDC_LOG_ERR("Failed to invoke sprintf_s for g_ppc_dirs.\n");
return;
}
#endif
if (mmAccess(g_ppc_dirs) == -1) {
hdc_create_dir_info_output();
#if defined (CFG_PLATFORM_EQUIP) && defined (CFG_SOC_PLATFORM_RC)
if (drv_hdc_ppc_check_user(user)) {
ret = mkdir((const char *)g_ppc_dirs, (mode_t)(S_IRWXU | S_IRGRP | S_IXGRP));
if (ret != 0) {
HDC_LOG_ERR("Try to mkdir failed(result=%d; errno=%d).\n", ret, errno);
}
}
#endif
}
return;
}
STATIC void __attribute__((constructor)) drv_hdc_socket_init(void)
{
drv_hdc_socket_create_dir();
}
STATIC drvError_t drv_hdc_socket_sock_path(struct sockaddr_un *addr, enum sock_type type, int dev_id,
const signed int pid, signed int *path_len)
{
const char *type_str = NULL;
signed int len = 0;
if ((addr == NULL) || (path_len == NULL)) {
#ifndef TMP_UT
HDC_LOG_ERR("Input parameter addr or path_len is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
#endif
}
type_str = type == SOCK_CLIENT ? "sock_client_" : "sock_server_";
if ((len = sprintf_s(addr->sun_path, sizeof(addr->sun_path), "%s%s%d_%d", g_ppc_dirs, type_str, pid, dev_id)) ==
-1) {
#ifndef TMP_UT
*path_len = 0;
HDC_LOG_ERR("Call sprintf_s failed.\n");
return DRV_ERROR_SOCKET_SET;
#endif
}
*path_len = (signed int)offsetof(struct sockaddr_un, sun_path) + len;
return DRV_ERROR_NONE;
}
drvError_t drv_hdc_socket_session_connect(int dev_id, signed int server_pid, PPC_SESSION *session)
{
struct hdc_client_session *pSession = NULL;
signed int fd = -1;
signed int len, ret;
drvError_t rval;
struct sockaddr_un srv_addr = {0};
if (session == NULL) {
#ifndef TMP_UT
HDC_LOG_ERR("Input parameter session is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
#endif
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
#ifndef TMP_UT
HDC_LOG_ERR("Create ppc socket error. (strerror=\"%s\"; errno=%d)\n", strerror(errno), errno);
return DRV_ERROR_SOCKET_CREATE;
#endif
}
srv_addr.sun_family = AF_UNIX;
if (drv_hdc_socket_sock_path(&srv_addr, SOCK_SERVER, dev_id, server_pid, &len) != DRV_ERROR_NONE) {
rval = DRV_ERROR_SOCKET_SET;
goto errout;
}
do {
ret = connect(fd, (struct sockaddr *)&srv_addr, (unsigned int)len);
} while ((ret == -1) && (mm_get_error_code() == EINTR));
if (ret < 0) {
rval = DRV_ERROR_SOCKET_CONNECT;
HDC_LOG_WARN("Connect ppc socket not success. (strerror=\"%s\"; errno=%d; server_pid=%d)\n",
strerror(errno), errno, server_pid);
goto errout;
}
#ifndef TMP_UT
pSession = (struct hdc_client_session *)drv_hdc_zalloc(sizeof(struct hdc_client_session));
if (pSession == NULL) {
rval = DRV_ERROR_MALLOC_FAIL;
HDC_LOG_ERR("Call malloc failed.\n");
goto errout;
}
HDC_LOG_INFO("Ppc connect session. (session_fd=%d; pid=%d)\n", fd, getpid());
pSession->session.magic = HDC_MAGIC_WORD;
pSession->session.sockfd = fd;
*session = (PPC_SESSION)pSession;
return DRV_ERROR_NONE;
#endif
errout:
(void)close(fd);
return rval;
}
drvError_t drv_hdc_socket_server_create(int dev_id, signed int server_pid, PPC_SERVER *server)
{
signed int len;
drvError_t rval;
signed int fd = -1;
struct hdc_server_head *pHead = NULL;
struct sockaddr_un srv_addr = {0};
if (server == NULL) {
#ifndef TMP_UT
HDC_LOG_ERR("Input parameter server is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
#endif
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
#ifndef TMP_UT
HDC_LOG_ERR("Create ppc socket error. (strerror=\"%s\"; errno=%d)\n", strerror(errno), errno);
return DRV_ERROR_SOCKET_CREATE;
#endif
}
srv_addr.sun_family = AF_UNIX;
if (drv_hdc_socket_sock_path(&srv_addr, SOCK_SERVER, dev_id, server_pid, &len) != DRV_ERROR_NONE) {
#ifndef TMP_UT
rval = DRV_ERROR_SOCKET_SET;
goto errout;
#endif
}
(void)unlink(srv_addr.sun_path);
if (bind(fd, (struct sockaddr *)&srv_addr, (unsigned int)len) < 0) {
#ifndef TMP_UT
rval = DRV_ERROR_SOCKET_BIND;
HDC_LOG_ERR("Bind ppc socket error. (strerror=\"%s\"; errno=%d; server_pid=%d)\n",
strerror(errno), errno, server_pid);
goto errout;
#endif
}
(void)chmod(srv_addr.sun_path, PPC_FILE_PERMISSION_WRITE);
if (listen(fd, QLEN) < 0) {
rval = DRV_ERROR_SOCKET_LISTEN;
HDC_LOG_ERR("Listen ppc socket error. (strerror=\"%s\"; errno=%d)\n", strerror(errno), errno);
goto errout;
}
#ifndef TMP_UT
pHead = (struct hdc_server_head *)drv_hdc_zalloc(sizeof(struct hdc_server_head));
if (pHead == NULL) {
rval = DRV_ERROR_MALLOC_FAIL;
HDC_LOG_ERR("Call malloc failed.\n");
goto errout;
}
HDC_LOG_INFO("Ppc Server Create. (Fd=%d; pid=%d)\n", fd, server_pid);
pHead->listenFd = fd;
pHead->accept_wait = HDC_ACCEPT_NOT_WAITING;
*server = (PPC_SERVER)pHead;
return DRV_ERROR_NONE;
#endif
errout:
(void)close(fd);
return rval;
}
drvError_t drv_hdc_socket_session_accept(PPC_SERVER server, PPC_SESSION *session)
{
struct hdc_server_head *pHead = NULL;
struct hdc_server_session *pSession = NULL;
signed int clifd = -1;
signed int len;
struct sockaddr_un un;
if ((server == NULL) || (session == NULL)) {
#ifndef TMP_UT
HDC_LOG_WARN("Input parameter server or session is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
#endif
}
pHead = (struct hdc_server_head *)server;
len = (int)sizeof(un);
pHead->accept_wait = HDC_ACCEPT_WAITING;
do {
clifd = accept(pHead->listenFd, (struct sockaddr *)&un, (socklen_t *)&len);
} while ((clifd == -1) && (mm_get_error_code() == EINTR));
if (clifd < 0) {
if (pHead->listenFd == -1) {
#ifndef TMP_UT
HDC_LOG_WARN("Server socket closed pHead\n");
pHead->accept_wait = HDC_ACCEPT_NOT_WAITING;
return DRV_ERROR_SOCKET_CLOSE;
#endif
}
HDC_LOG_ERR("Accept ppc socket error. (strerror=\"%s\"; errno=%d; listenFd=%d)\n",
strerror(errno), errno, pHead->listenFd);
pHead->accept_wait = HDC_ACCEPT_NOT_WAITING;
return DRV_ERROR_SOCKET_ACCEPT;
}
#ifndef TMP_UT
HDC_LOG_INFO("Ppc Accept Session. (clifd=%d; Server_fd=%d; pid=%d)\n", clifd, pHead->listenFd, getpid());
pHead->accept_wait = HDC_ACCEPT_NOT_WAITING;
pSession = (struct hdc_server_session *)malloc(sizeof(struct hdc_server_session));
if (pSession == NULL) {
HDC_LOG_ERR("Call malloc failed.\n");
(void)close(clifd);
clifd = -1;
return DRV_ERROR_MALLOC_FAIL;
}
if (memset_s(pSession, sizeof(struct hdc_server_session), 0, sizeof(struct hdc_server_session)) != 0) {
free(pSession);
pSession = NULL;
(void)close(clifd);
clifd = -1;
HDC_LOG_ERR("Call memset_s error. (strerror=\"%s\")\n", strerror(errno));
return DRV_ERROR_INVALID_VALUE;
}
pSession->session.magic = HDC_MAGIC_WORD;
pSession->session.sockfd = clifd;
*session = (PPC_SESSION)pSession;
return DRV_ERROR_NONE;
#endif
}