1 /*
2 * Copyright (c) 2021-2022 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 "appspawn_socket.h"
17
18 #include <sys/socket.h>
19 #include <linux/tcp.h>
20 #include <linux/in.h>
21 #include <cerrno>
22
23 #include "appspawn_server.h"
24 #include "pubdef.h"
25 #include "securec.h"
26
27 namespace OHOS {
28 namespace AppSpawn {
AppSpawnSocket(const std::string & name)29 AppSpawnSocket::AppSpawnSocket(const std::string &name)
30 {
31 socketName_ = name;
32 }
33
~AppSpawnSocket()34 AppSpawnSocket::~AppSpawnSocket()
35 {
36 if (socketFd_ > 0) {
37 CloseSocket(socketFd_);
38 socketFd_ = -1;
39 }
40 }
41
GetSocketFd() const42 int AppSpawnSocket::GetSocketFd() const
43 {
44 return socketFd_;
45 }
46
PackSocketAddr()47 int AppSpawnSocket::PackSocketAddr()
48 {
49 APPSPAWN_CHECK(!socketName_.empty(), return -EINVAL, "Invalid socket name: empty");
50 (void)memset_s(&socketAddr_, sizeof(socketAddr_), 0, sizeof(socketAddr_));
51
52 socklen_t pathLen = 0;
53 if (socketName_[0] == '/') {
54 pathLen = socketName_.length();
55 } else {
56 pathLen = socketDir_.length() + socketName_.length();
57 }
58 socklen_t pathSize = sizeof(socketAddr_.sun_path);
59 if (pathLen >= pathSize) {
60 APPSPAWN_LOGE("Invalid socket name: '%{public}s' too long", socketName_.c_str());
61 return -1;
62 }
63
64 int len = 0;
65 if (socketName_[0] == '/') {
66 len = snprintf_s(socketAddr_.sun_path, pathSize, (pathSize - 1), "%s", socketName_.c_str());
67 } else {
68 len = snprintf_s(socketAddr_.sun_path, pathSize, (pathSize - 1), "%s%s",
69 socketDir_.c_str(), socketName_.c_str());
70 }
71 APPSPAWN_CHECK(static_cast<int>(pathLen) == len, return -1, "Failed to copy socket path");
72
73 socketAddr_.sun_family = AF_LOCAL;
74 socketAddrLen_ = offsetof(struct sockaddr_un, sun_path) + pathLen + 1;
75
76 return 0;
77 }
78
CreateSocket()79 int AppSpawnSocket::CreateSocket()
80 {
81 int socketFd = socket(AF_UNIX, SOCK_STREAM, 0); // SOCK_SEQPACKET
82 APPSPAWN_CHECK(socketFd >= 0, return -errno, "Failed to create socket: %{public}d", errno);
83
84 int flag = 1;
85 int ret = setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
86 APPSPAWN_LOGV("Created socket with fd %{public}d, setsockopt %{public}d", socketFd, ret);
87 return socketFd;
88 }
89
CloseSocket(int & socketFd)90 void AppSpawnSocket::CloseSocket(int &socketFd)
91 {
92 if (socketFd >= 0) {
93 APPSPAWN_LOGV("Closed socket with fd %{public}d", socketFd);
94 int flag = 0;
95 setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
96 close(socketFd);
97 socketFd = -1;
98 }
99 }
100
ReadSocketMessage(int socketFd,void * buf,int len)101 int AppSpawnSocket::ReadSocketMessage(int socketFd, void *buf, int len)
102 {
103 if (socketFd < 0 || len <= 0 || buf == nullptr) {
104 APPSPAWN_LOGE("Invalid args: socket %{public}d, len %{public}d, buf might be nullptr", socketFd, len);
105 return -1;
106 }
107
108 APPSPAWN_CHECK(memset_s(buf, len, 0, len) == EOK, return -1, "Failed to memset read buf");
109
110 ssize_t rLen = TEMP_FAILURE_RETRY(read(socketFd, buf, len));
111 while ((rLen < 0) && (errno == EAGAIN)) {
112 rLen = TEMP_FAILURE_RETRY(read(socketFd, buf, len));
113 }
114 APPSPAWN_CHECK(rLen >= 0, return -EFAULT,
115 "Read message from fd %{public}d error %{public}zd: %{public}d", socketFd, rLen, errno);
116
117 return rLen;
118 }
119
WriteSocketMessage(int socketFd,const void * buf,int len)120 int AppSpawnSocket::WriteSocketMessage(int socketFd, const void *buf, int len)
121 {
122 if (socketFd < 0 || len <= 0 || buf == nullptr) {
123 APPSPAWN_LOGE("Invalid args: socket %{public}d, len %{public}d, buf might be nullptr", socketFd, len);
124 return -1;
125 }
126
127 ssize_t written = 0;
128 ssize_t remain = static_cast<ssize_t>(len);
129 const uint8_t *offset = reinterpret_cast<const uint8_t *>(buf);
130 for (ssize_t wLen = 0; remain > 0; offset += wLen, remain -= wLen, written += wLen) {
131 wLen = write(socketFd, offset, remain);
132 APPSPAWN_LOGV("socket fd %{public}d, wLen %{public}zd", socketFd, wLen);
133 bool isRet = (wLen <= 0) && (errno != EINTR);
134 APPSPAWN_CHECK(!isRet, return -errno,
135 "Failed to write message to fd %{public}d, error %{public}zd: %{public}d", socketFd, wLen, errno);
136 }
137
138 return written;
139 }
140 } // namespace AppSpawn
141 } // namespace OHOS
142