2 * Copyright (c) 2017 Samsung Electronics Co.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
18 * @author Bartlomiej Grzelewski <b.grzelewski@samsung.com>
19 * @brief The implementation of Sock.
23 #include <sys/socket.h>
27 #ifdef BUILD_WITH_SYSTEMD_DAEMON
28 #include <systemd/sd-daemon.h>
29 #endif // BUILD_WITH_SYSTEMD_DAEMON
34 #include <askuser-notification/ask-user-types.h>
35 #include <askuser-notification/sock.h>
40 Sock::Sock(Sock &&second)
41 : m_type(second.m_type)
47 Sock::Sock(Sock::Type type, int fd)
52 Sock& Sock::operator=(Sock &&second) {
59 m_type = second.m_type;
67 int Sock::getUnixSockType() const {
79 int Sock::getSocketFromSystemD() const {
80 #ifdef BUILD_WITH_SYSTEMD_DAEMON
81 int n = sd_listen_fds(0);
86 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd)
87 if (0 < sd_is_socket_unix(fd, getUnixSockType(), -1, m_path.c_str(), 0))
89 #endif // BUILD_WITH_SYSTEMD_DAEMON
93 int Sock::connect(const std::string &path) {
99 bool policySystemD = true;
100 bool policyUnlink = true;
101 bool policySocket = true;
102 bool policyBind = true;
103 bool policyListen = true;
104 bool policyConnect = true;
108 policyConnect = false;
111 policySystemD = false;
112 policyUnlink = false;
114 policyListen = false;
117 policyListen = false;
118 policyConnect = false;
121 policySystemD = false;
122 policyUnlink = false;
124 policyListen = false;
125 policyConnect = false;
130 m_fd = getSocketFromSystemD();
132 policyUnlink = false;
133 policySocket = false;
139 ::unlink(m_path.c_str()); // we ignore return value by design
142 m_fd = ::socket(AF_UNIX, getUnixSockType(), 0);
147 // remote is used in bind and in connect
149 auto length = sizeof(sockaddr_un);
150 if (policyBind || policyConnect) {
151 remote.sun_family = AF_UNIX;
152 if (path.size() >= sizeof(remote.sun_path)) {
156 memcpy(remote.sun_path, path.c_str(), path.size()+1);
159 if (policyBind && (-1 == ::bind(m_fd, reinterpret_cast<sockaddr *>(&remote), sizeof(remote)))) {
164 if (policyListen && (-1 == ::listen(m_fd, 5))) {
169 if (policyConnect && (-1 == TEMP_FAILURE_RETRY(::connect(m_fd, reinterpret_cast<sockaddr *>(&remote), static_cast<socklen_t>(length)))))
177 Sock Sock::accept() {
178 int retFd = TEMP_FAILURE_RETRY(::accept(m_fd, nullptr, nullptr));
180 return Sock(CLI_STREAM, -1);
182 return Sock(CLI_STREAM, retFd);
185 int Sock::send(const RawBuffer &buffer) {
186 static const int flags = MSG_NOSIGNAL | MSG_DONTWAIT;
195 return static_cast<int>(
196 TEMP_FAILURE_RETRY(::send(m_fd, buffer.data(), buffer.size(), flags)));
200 struct sockaddr_un addr;
201 memset(&addr, 0, sizeof(addr));
202 addr.sun_family = AF_UNIX;
203 memcpy(addr.sun_path, m_path.data(), m_path.size());
204 return static_cast<int>(
205 TEMP_FAILURE_RETRY(::sendto(m_fd, buffer.data(), buffer.size(), flags,
206 reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr))));
211 int Sock::wait(int mask) {
212 pollfd fd = {0, 0, 0};
215 fd.events = (mask & FdMask::READ ? POLLIN : 0) | (mask & FdMask::WRITE ? POLLOUT : 0);
220 if (0 > ::poll(&fd, 1, -1))
225 int Sock::recv(RawBuffer &output) {
235 RawBuffer buffer(4096);
236 int result = TEMP_FAILURE_RETRY(::recv(m_fd, buffer.data(), buffer.size(), MSG_DONTWAIT));
238 std::copy(buffer.begin(), buffer.begin()+result, std::back_inserter(output));
239 return static_cast<int>(result);
250 } // namespace Protocol
251 } // namespace AskUser