1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "easy_socket_writer.h"
17 
18 #include <errno.h>
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <string.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <unistd.h>
25 
26 #include "easy_def.h"
27 #include "easy_util.h"
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 static const char SOCKET_PATH[] = "/dev/unix/socket/hisysevent";
34 
InitSendBuffer(int socketId)35 static int InitSendBuffer(int socketId)
36 {
37     int sendBuffSize = 384 * 1024; // max buffer of socket is 384K
38     if (setsockopt(socketId, SOL_SOCKET, SO_SNDBUF, (void*)(&sendBuffSize), sizeof(int)) < 0) {
39         return ERR_SET_SOCKET_OPT_FAILED;
40     }
41     return SUCCESS;
42 }
43 
InitSocket(struct sockaddr_un* socketAddr)44 static int InitSocket(struct sockaddr_un* socketAddr)
45 {
46     if (socketAddr == NULL) {
47         return ERR_SOCKET_ADDR_INVALID;
48     }
49     int ret = MemoryInit((uint8_t*)(socketAddr), sizeof(struct sockaddr_un));
50     if (ret != SUCCESS) {
51         return ret;
52     }
53     ret = MemoryCopy((uint8_t*)(socketAddr->sun_path), sizeof(socketAddr->sun_path), (uint8_t*)SOCKET_PATH,
54         strlen(SOCKET_PATH));
55     if (ret != SUCCESS) {
56         return ret;
57     }
58     socketAddr->sun_family = AF_UNIX;
59     return SUCCESS;
60 }
61 
Write(const uint8_t* data, const size_t dataLen)62 int Write(const uint8_t* data, const size_t dataLen)
63 {
64     if (data == NULL) {
65         return ERR_EVENT_BUF_INVALID;
66     }
67     int socketId = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
68     if (socketId < 0) {
69         close(socketId);
70         return ERR_INIT_SOCKET_FAILED;
71     }
72     int ret = InitSendBuffer(socketId);
73     if (ret != SUCCESS) {
74         close(socketId);
75         return ret;
76     }
77     struct sockaddr_un socketAddr;
78     ret = InitSocket(&socketAddr);
79     if (ret != SUCCESS) {
80         close(socketId);
81         return ret;
82     }
83 
84     int sendRet = 0;
85     int retryTimes = 3; // retry 3 times to write socket
86     do {
87         sendRet = sendto(socketId, data, dataLen, 0, (struct sockaddr*)(&socketAddr),
88             sizeof(socketAddr));
89         retryTimes--;
90     } while (sendRet < 0 && retryTimes > 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR));
91     if (sendRet < 0) {
92         close(socketId);
93         return ERR_SOCKET_SEND_ERROR_BASE + errno;
94     }
95     close(socketId);
96     return SUCCESS;
97 }
98 
99 #ifdef __cplusplus
100 }
101 #endif