Remove superfluous check in Sock
[platform/core/security/askuser.git] / src / ipc-lib / sock.cpp
1 /*
2  *  Copyright (c) 2017 Samsung Electronics Co.
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  */
16 /**
17  * @file        sock.cpp
18  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
19  * @brief       The implementation of Sock.
20  */
21 #include <poll.h>
22 #include <stdexcept>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <unistd.h>
26
27 #ifdef BUILD_WITH_SYSTEMD_DAEMON
28 #include <systemd/sd-daemon.h>
29 #endif // BUILD_WITH_SYSTEMD_DAEMON
30
31 #include <string>
32 #include <vector>
33
34 #include <askuser-notification/ask-user-types.h>
35 #include <askuser-notification/sock.h>
36
37 namespace AskUser {
38 namespace Protocol {
39
40 Sock::Sock(Sock &&second)
41   : m_type(second.m_type)
42   , m_fd(second.m_fd)
43 {
44     second.m_fd = -1;
45 }
46
47 Sock::Sock(Sock::Type type, int fd)
48   : m_type(type)
49   , m_fd(fd)
50 {}
51
52 Sock& Sock::operator=(Sock &&second) {
53     if (this == &second)
54         return *this;
55
56     close();
57
58     m_fd = second.m_fd;
59     m_type = second.m_type;
60
61     second.m_fd = -1;
62
63     return *this;
64 }
65
66
67 int Sock::getUnixSockType() const {
68     switch(m_type) {
69     case SRV_DGRAM:
70     case CLI_DGRAM:
71         return SOCK_DGRAM;
72     case SRV_STREAM:
73     case CLI_STREAM:
74         return SOCK_STREAM;
75     }
76     return 0;
77 }
78
79 int Sock::getSocketFromSystemD() const {
80 #ifdef BUILD_WITH_SYSTEMD_DAEMON
81     int n = sd_listen_fds(0);
82
83     if (n < 0)
84         return -1;
85
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))
88             return fd;
89 #endif // BUILD_WITH_SYSTEMD_DAEMON
90     return -1;
91 }
92
93 int Sock::connect(const std::string &path) {
94     if (m_fd != -1)
95         return -1;
96
97     m_path = path;
98
99     bool policySystemD = true;
100     bool policyUnlink  = true;
101     bool policySocket  = true;
102     bool policyBind    = true;
103     bool policyListen  = true;
104     bool policyConnect = true;
105
106     switch(m_type) {
107     case SRV_STREAM:
108         policyConnect = false;
109         break;
110     case CLI_STREAM:
111         policySystemD = false;
112         policyUnlink  = false;
113         policyBind    = false;
114         policyListen  = false;
115         break;
116     case SRV_DGRAM:
117         policyListen  = false;
118         policyConnect = false;
119         break;
120     case CLI_DGRAM:
121         policySystemD = false;
122         policyUnlink  = false;
123         policyBind    = false;
124         policyListen  = false;
125         policyConnect = false;
126         break;
127     }
128
129     if (policySystemD) {
130         m_fd = getSocketFromSystemD();
131         if (m_fd >= 0) {
132             policyUnlink = false;
133             policySocket = false;
134             policyBind = false;
135         }
136     }
137
138     if (policyUnlink)
139         ::unlink(m_path.c_str());  // we ignore return value by design
140
141     if (policySocket)
142         m_fd = ::socket(AF_UNIX, getUnixSockType(), 0);
143
144     if (m_fd < 0)
145         return -1;
146
147     // remote is used in bind and in connect
148     sockaddr_un remote;
149     auto length = sizeof(sockaddr_un);
150     if (policyBind || policyConnect) {
151         remote.sun_family = AF_UNIX;
152         if (path.size() >= sizeof(remote.sun_path)) {
153             close();
154             return -1;
155         }
156         memcpy(remote.sun_path, path.c_str(), path.size()+1);
157     }
158
159     if (policyBind && (-1 == ::bind(m_fd, reinterpret_cast<sockaddr *>(&remote), sizeof(remote)))) {
160         close();
161         return -1;
162     }
163
164     if (policyListen && (-1 == ::listen(m_fd, 5))) {
165         close();
166         return -1;
167     }
168
169     if (policyConnect && (-1 == TEMP_FAILURE_RETRY(::connect(m_fd, reinterpret_cast<sockaddr *>(&remote), static_cast<socklen_t>(length)))))
170     {
171         close();
172         return -1;
173     }
174     return 0;
175 }
176
177 Sock Sock::accept() {
178     int retFd = TEMP_FAILURE_RETRY(::accept(m_fd, nullptr, nullptr));
179     if (retFd < 0) {
180         return Sock(CLI_STREAM, -1);
181     }
182     return Sock(CLI_STREAM, retFd);
183 }
184
185 int Sock::send(const RawBuffer &buffer) {
186     static const int flags = MSG_NOSIGNAL | MSG_DONTWAIT;
187     if (m_fd < 0)
188         return -1;
189
190     switch(m_type) {
191     default:
192         return -1;
193     case CLI_STREAM:
194         {
195             return static_cast<int>(
196                 TEMP_FAILURE_RETRY(::send(m_fd, buffer.data(), buffer.size(), flags)));
197         }
198     case CLI_DGRAM:
199         {
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))));
207         }
208     }
209 }
210
211 int Sock::wait(int mask) {
212     pollfd fd = {0, 0, 0};
213
214     fd.fd = m_fd;
215     fd.events = (mask & FdMask::READ ? POLLIN : 0) | (mask & FdMask::WRITE ? POLLOUT : 0);
216
217     if (fd.events == 0)
218         return -1;
219
220     if (0 > ::poll(&fd, 1, -1))
221         return -1;
222     return 0;
223 }
224
225 int Sock::recv(RawBuffer &output) {
226     if (m_fd < 0)
227         return -1;
228
229     switch(m_type) {
230     default:
231         return -1;
232     case CLI_STREAM:
233     case SRV_DGRAM:
234         {
235             RawBuffer buffer(4096);
236             int result = TEMP_FAILURE_RETRY(::recv(m_fd, buffer.data(), buffer.size(), MSG_DONTWAIT));
237             if (result > 0)
238                 std::copy(buffer.begin(), buffer.begin()+result, std::back_inserter(output));
239             return static_cast<int>(result);
240         }
241     }
242 }
243
244 void Sock::close() {
245     if (m_fd >= 0)
246         ::close(m_fd);
247     m_fd = -1;
248 }
249
250 } // namespace Protocol
251 } // namespace AskUser
252