The aul sock is implemented using C++.
Change-Id: I34573294f754e2469d19bd2867f89a6d7f88bc51
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
error_code_ = error_code;
message_ = file.substr(file.find_last_of("/") + 1) + ":"
+ std::to_string(line) + " code:" + std::to_string(error_code_);
- _E("%s", message_.c_str());
}
virtual ~Exception() {}
return message_.c_str();
}
- int GetErrorCode() {
+ int GetErrorCode() const {
return error_code_;
}
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aul/socket/client_socket.hh"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+namespace aul {
+namespace {
+
+constexpr const int MAX_RETRY_CNT = 2;
+
+} // namespace
+
+ClientSocket::ClientSocket() {
+ fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd_ < 0) {
+ int error = -errno;
+ _E("socket() is failed. errno(%d)", errno);
+ THROW(error);
+ }
+}
+
+ClientSocket::ClientSocket(int fd) : fd_(fd) {}
+
+ClientSocket::~ClientSocket() {
+ Close();
+}
+
+void ClientSocket::Close() {
+ if (fd_ > -1) {
+ close(fd_);
+ fd_ = -1;
+ }
+}
+
+void ClientSocket::Connect(const std::string& endpoint) {
+ int flag = fcntl(fd_, F_GETFL, 0);
+ fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK);
+
+ struct sockaddr_un sockaddr = { 0, };
+ sockaddr.sun_family = AF_UNIX;
+ snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s",
+ endpoint.c_str());
+ struct sockaddr* sockaddr_ptr = reinterpret_cast<struct sockaddr*>(&sockaddr);
+ socklen_t len = sizeof(sockaddr);
+
+ int ret;
+ int retry = 2;
+ do {
+ ret = connect(fd_, sockaddr_ptr, len);
+ if (ret == 0)
+ break;
+
+ retry--;
+ usleep(100 * 1000);
+ } while (retry > 0);
+
+ fcntl(fd_, F_SETFL, flag);
+ if (ret < 0) {
+ ret = -errno;
+ _E("connect() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+int ClientSocket::Send(const void* buf, unsigned int size) {
+ const unsigned char* buffer = static_cast<const unsigned char*>(buf);
+ size_t len = size;
+ int retry_cnt = MAX_RETRY_CNT;
+ while (len) {
+ ssize_t bytes = send(fd_, buffer, len, MSG_NOSIGNAL | MSG_DONTWAIT);
+ if (bytes < 0) {
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+ if (retry_cnt > 0) {
+ retry_cnt--;
+ _E("send(): fd(%d), errno(%d). sleep and retry ...", fd_, errno);
+ usleep(10 * 1000);
+ continue;
+ }
+ }
+
+ _E("send() is failed. fd(%d), errno(%d)", fd_, errno);
+ return -ECOMM;
+ }
+
+ len -= bytes;
+ buffer += bytes;
+ }
+
+ return 0;
+}
+
+int ClientSocket::Receive(void* buf, unsigned int size) {
+ bool is_blocking;
+ if (fcntl(fd_, F_GETFL, 0) & O_NONBLOCK)
+ is_blocking = false;
+ else
+ is_blocking = true;
+
+ int retry_count = 20;
+ unsigned char* buffer = static_cast<unsigned char*>(buf);
+ size_t len = size;
+ while (len) {
+ ssize_t bytes = recv(fd_, buffer, len, 0);
+ if (bytes == 0) {
+ _W("EOF. fd(%d)", fd_);
+ return -ECOMM;
+ }
+
+ if (bytes < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ if (is_blocking && errno == EAGAIN) {
+ _E("Timed out. fd(%d)", fd_);
+ return -EAGAIN;
+ }
+
+ if (retry_count > 0) {
+ usleep(100 * 1000);
+ retry_count--;
+ continue; }
+ }
+
+ _E("recv() is failed. fd(%d), errno(%d)", fd_, errno);
+ return -ECOMM;
+ }
+
+ len -= bytes;
+ buffer += bytes;
+ }
+
+ return 0;
+}
+
+int ClientSocket::GetReceiveBufferSize() {
+ int value;
+ socklen_t len = sizeof(int);
+ int ret = getsockopt(fd_, SOL_SOCKET, SO_RCVBUF,
+ reinterpret_cast<void*>(&value), &len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("getsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+
+ return value;
+}
+
+int ClientSocket::GetSendBufferSize() {
+ int value;
+ socklen_t len = sizeof(int);
+ int ret = getsockopt(fd_, SOL_SOCKET, SO_SNDBUF,
+ reinterpret_cast<void*>(&value), &len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("getsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+
+ return value;
+}
+
+int ClientSocket::GetReceiveTimeout() {
+ struct timeval timeout = { 0, };
+ socklen_t len = sizeof(struct timeval);
+ int ret = getsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO,
+ reinterpret_cast<void*>(&timeout), &len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("getsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+
+ int value = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
+ return value;
+}
+
+void ClientSocket::SetReceiveBufferSize(int size) {
+ socklen_t len = sizeof(size);
+ int ret = setsockopt(fd_, SOL_SOCKET, SO_RCVBUF, &size, len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("setsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+void ClientSocket::SetSendBufferSize(int size) {
+ socklen_t len = sizeof(size);
+ int ret = setsockopt(fd_, SOL_SOCKET, SO_SNDBUF, &size, len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("setsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+void ClientSocket::SetReceiveTimeout(int timeout) {
+ if (timeout == INT_MAX)
+ return;
+
+ if (timeout == -1)
+ timeout = 5000;
+
+ if (timeout < 0) {
+ _E("Invalid parameter");
+ THROW(-EINVAL);
+ }
+
+ struct timeval tv = {
+ .tv_sec = static_cast<time_t>(timeout / 1000),
+ .tv_usec = static_cast<suseconds_t>((timeout % 1000) * 1000)
+ };
+ socklen_t len = sizeof(struct timeval);
+ int ret = setsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO, &tv, len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("setsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+bool ClientSocket::IsClosed() {
+ return fd_ < 0;
+}
+
+int ClientSocket::GetFd() const {
+ return fd_;
+}
+
+int ClientSocket::RemoveFd() {
+ int fd = fd_;
+ fd_ = -1;
+ return fd;
+}
+
+} // namespace aul
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUL_SOCKET_CLIENT_SOCKET_HH_
+#define AUL_SOCKET_CLIENT_SOCKET_HH_
+
+#include <memory>
+#include <string>
+
+#include "aul/common/exception.hh"
+
+namespace aul {
+
+class ClientSocket {
+ public:
+ ClientSocket();
+ explicit ClientSocket(int fd);
+ virtual ~ClientSocket();
+
+ void Close();
+ void Connect(const std::string& endpoint);
+ int Send(const void* buf, unsigned int size);
+ int Receive(void* buf, unsigned int size);
+ int GetReceiveBufferSize();
+ int GetSendBufferSize();
+ int GetReceiveTimeout();
+ void SetReceiveBufferSize(int size);
+ void SetSendBufferSize(int size);
+ void SetReceiveTimeout(int timeout);
+ bool IsClosed();
+ int GetFd() const;
+ int RemoveFd();
+
+ private:
+ int fd_;
+};
+
+} // namespace aul
+
+#endif // AUL_SOCKET_CLIENT_SOCKET_HH_
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aul/socket/server_socket.hh"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "aul/common/exception.hh"
+#include "aul/common/log_private.hh"
+
+namespace aul {
+
+ServerSocket::ServerSocket() {
+ fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ if (fd_ < 0) {
+ fd_ = -errno;
+ _E("socket() is failed. errno(%d)", errno);
+ THROW(fd_);
+ }
+}
+
+ServerSocket::ServerSocket(int fd) : fd_(fd) {}
+
+ServerSocket::~ServerSocket() {
+ Close();
+}
+
+ClientSocket* ServerSocket::Accept() {
+ struct sockaddr_un addr = { 0, };
+ socklen_t len = sizeof(struct sockaddr_un);
+ auto* addr_ptr = reinterpret_cast<struct sockaddr*>(&addr);
+ int client_fd = accept(GetFd(), addr_ptr, &len);
+ if (client_fd == -1) {
+ _E("accept() is failed. errno(%d)", errno);
+ return nullptr;
+ }
+
+ return new (std::nothrow) ClientSocket(client_fd);
+}
+
+void ServerSocket::Bind(const std::string& bindpoint) {
+ struct sockaddr_un sockaddr = { 0, };
+ sockaddr.sun_family = AF_UNIX;
+ snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s",
+ bindpoint.c_str());
+ struct sockaddr* sockaddr_ptr = reinterpret_cast<struct sockaddr*>(&sockaddr);
+ socklen_t len = sizeof(sockaddr);
+
+ unlink(bindpoint.c_str());
+ int ret = bind(GetFd(), sockaddr_ptr, len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("bind() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+void ServerSocket::Close() {
+ if (fd_ > -1) {
+ close(fd_);
+ fd_ = -1;
+ }
+}
+
+void ServerSocket::Listen(int backlog) {
+ int ret = listen(fd_, backlog);
+ if (ret < 0) {
+ ret = -errno;
+ _E("listen() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+int ServerSocket::GetReceiveBufferSize() {
+ int value;
+ socklen_t len = sizeof(int);
+ int ret = getsockopt(fd_, SOL_SOCKET, SO_RCVBUF,
+ reinterpret_cast<void*>(&value), &len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("getsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+
+ return value;
+}
+
+int ServerSocket::GetSendBufferSize() {
+ int value;
+ socklen_t len = sizeof(int);
+ int ret = getsockopt(fd_, SOL_SOCKET, SO_SNDBUF,
+ reinterpret_cast<void*>(&value), &len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("getsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+
+ return value;
+}
+
+void ServerSocket::SetReceiveBufferSize(int size) {
+ socklen_t len = sizeof(size);
+ int ret = setsockopt(fd_, SOL_SOCKET, SO_RCVBUF, &size, len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("setsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+void ServerSocket::SetSendBufferSize(int size) {
+ socklen_t len = sizeof(size);
+ int ret = setsockopt(fd_, SOL_SOCKET, SO_SNDBUF, &size, len);
+ if (ret < 0) {
+ ret = -errno;
+ _E("setsockopt() is failed. errno(%d)", errno);
+ THROW(ret);
+ }
+}
+
+bool ServerSocket::IsClosed() {
+ return fd_ < 0;
+}
+
+int ServerSocket::GetFd() const {
+ return fd_;
+}
+
+int ServerSocket::RemoveFd() {
+ int fd = fd_;
+ fd_ = -1;
+ return fd;
+}
+
+} // namespace aul
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUL_SOCKET_SERVER_SOCKET_HH_
+#define AUL_SOCKET_SERVER_SOCKET_HH_
+
+#include <memory>
+#include <string>
+
+#include "aul/common/exception.hh"
+#include "aul/socket/client_socket.hh"
+
+namespace aul {
+
+class ServerSocket {
+ public:
+ ServerSocket();
+ explicit ServerSocket(int fd);
+ virtual ~ServerSocket();
+
+ ClientSocket* Accept();
+ void Bind(const std::string& bindpoint);
+ void Close();
+ void Listen(int backlog);
+ int GetReceiveBufferSize();
+ int GetSendBufferSize();
+ void SetReceiveBufferSize(int size);
+ void SetSendBufferSize(int size);
+ bool IsClosed();
+ int GetFd() const;
+ int RemoveFd();
+
+ private:
+ int fd_;
+};
+
+} // namespace aul
+
+#endif // AUL_SOCKET_SERVER_SOCKET_HH_
return -1;
}
-int Socket::GetFd() {
+int Socket::GetFd() const {
return fd_;
}
-std::string Socket::GetPath() {
+const std::string& Socket::GetPath() const {
return path_;
}
+int Socket::RemoveFd() {
+ int fd = fd_;
+ fd_ = -1;
+ return fd;
+}
+
void Socket::SetOption() {
int size = MAX_AUL_BUFF_SIZE;
int ret = setsockopt(fd_, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
int Listen();
int Connect();
- int GetFd();
+ int GetFd() const;
void SetTimeout(int timeout_msec);
- std::string GetPath();
+ const std::string& GetPath() const;
+ int RemoveFd();
private:
void SetOption();
+++ /dev/null
-/*
- * Copyright (c) 2000 - 2018 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-#include <tzplatform_config.h>
-#include <glib.h>
-#include <vconf.h>
-
-#include "aul_api.h"
-#include "aul_sock.h"
-#include "aul_util.h"
-
-#define MAX_NR_OF_DESCRIPTORS 2
-#define MAX_PAYLOAD_SIZE (1024 * 1024 * 1)
-#define PATH_AMD_SOCK "/run/aul/daemons/.amd-sock"
-
-#define REGULAR_UID_MIN 5000
-
-typedef struct app_pkt_header_s {
- int cmd;
- int len;
- int opt;
-} app_pkt_header_t;
-
-static int socket_timeout_initialized;
-static int socket_link_created;
-static char socket_link_path[108];
-
-static struct timeval tv = { 5, 200 * 1000 }; /* 5.2 */
-
-static int __connect_client_sock(int sockfd, const struct sockaddr *saptr,
- socklen_t salen, int nsec);
-
-static int __recv_raw(int fd, unsigned char *data, size_t data_size)
-{
- ssize_t recv_size = 0;
- ssize_t r;
- size_t size = data_size;
- bool is_blocking;
- int retry_count = 20;
-
- if (fcntl(fd, F_GETFL, 0) & O_NONBLOCK)
- is_blocking = false;
- else
- is_blocking = true;
-
- while (size > 0) {
- r = recv(fd, data, size, 0);
- if (r == 0) {
- _W("Socket was disconnected. fd(%d)", fd);
- return -ECOMM;
- } else if (r < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- if (is_blocking && errno == EAGAIN) {
- _E("recv timeout. fd(%d)", fd);
- return -EAGAIN;
- }
-
- if (retry_count > 0) {
- usleep(100 * 1000);
- retry_count--;
- continue;
- }
- }
-
- _E("recv error. fd(%d), errno(%d)",
- fd, errno);
- return -ECOMM;
- }
-
- size -= r;
- data += r;
- recv_size += r;
- }
-
- if (recv_size != data_size) {
- _E("Failed to receive messages. fd(%d)", fd);
- return -ECOMM;
- }
-
- return 0;
-}
-
-static int __recv_pkt(int fd, app_pkt_t **out_pkt)
-{
- app_pkt_header_t header = { 0, };
- app_pkt_t *pkt;
- int r;
-
- *out_pkt = NULL;
- r = __recv_raw(fd, (unsigned char *)&header, sizeof(header));
- if (r < 0) {
- _E("Failed to receive packet header");
- return r;
- }
-
- if (header.len < 0 || header.len > MAX_PAYLOAD_SIZE) {
- _E("Invalid protocol. length(%d)", header.len);
- return -ECOMM;
- }
-
- pkt = calloc(1, sizeof(app_pkt_t) + header.len);
- if (!pkt) {
- _E("Out of memory");
- return -ECOMM;
- }
- pkt->cmd = header.cmd;
- pkt->len = header.len;
- pkt->opt = header.opt;
-
- r = __recv_raw(fd, (unsigned char *)pkt->data, pkt->len);
- if (r < 0) {
- free(pkt);
- return r;
- }
-
- *out_pkt = pkt;
-
- return 0;
-}
-
-static void __set_timeval(double sec)
-{
- char buf[12];
- gchar *ptr = NULL;
-
- snprintf(buf, sizeof(buf), "%.3f", sec);
- tv.tv_sec = g_ascii_strtoull(buf, &ptr, 10);
- tv.tv_usec = g_ascii_strtoull(ptr + 1, &ptr, 10) * 1000;
- _D("tv_sec: %ld, tv_usec: %ld", (long)tv.tv_sec, (long)tv.tv_usec);
-}
-
-static void __socket_timeout_vconf_cb(keynode_t *key, void *data)
-{
- const char *name;
- double sec;
-
- name = vconf_keynode_get_name(key);
- if (name && strcmp(name, VCONFKEY_AUL_SOCKET_TIMEOUT) == 0) {
- sec = vconf_keynode_get_dbl(key);
- __set_timeval(sec);
- }
-}
-
-static void __init_socket_timeout(void)
-{
- int r;
- double sec = 5.2f;
-
- r = access("/run/aul/.socket_timeout", F_OK);
- if (r < 0) {
- socket_timeout_initialized = 1;
- return;
- }
-
- r = vconf_get_dbl(VCONFKEY_AUL_SOCKET_TIMEOUT, &sec);
- if (r < 0)
- _D("Failed to get vconf: %s", VCONFKEY_AUL_SOCKET_TIMEOUT);
-
- r = vconf_notify_key_changed(VCONFKEY_AUL_SOCKET_TIMEOUT,
- __socket_timeout_vconf_cb, NULL);
- if (r < 0) {
- _E("Failed to register callback for %s",
- VCONFKEY_AUL_SOCKET_TIMEOUT);
- return;
- }
-
- __set_timeval(sec);
- socket_timeout_initialized = 1;
-}
-
-API struct timeval aul_sock_get_rcv_timeval(void)
-{
- return tv;
-}
-
-API int aul_sock_set_sock_option(int fd, int cli)
-{
- int size;
- int r;
-
- size = AUL_SOCK_MAXBUFF;
- r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
- if (r < 0)
- return r;
-
- r = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
- if (r < 0)
- return r;
-
- if (cli) {
- if (TIZEN_FEATURE_SOCKET_TIMEOUT && !socket_timeout_initialized)
- __init_socket_timeout();
- r = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int __create_socket_dir(int pid, uid_t uid)
-{
- char path[108];
-
- if (uid < REGULAR_UID_MIN)
- snprintf(path, sizeof(path), "/run/aul/daemons/%d", uid);
- else
- snprintf(path, sizeof(path), "/run/aul/apps/%d/%d", uid, pid);
-
- if (mkdir(path, 0700) != 0) {
- if (errno == EEXIST) {
- if (access(path, R_OK) != 0) {
- _E("Failed to acess %s directory", path);
- return -1;
- }
- } else {
- _E("Failed to create %s directory", path);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void __create_socket_path(char *path_buf, int size, int pid, uid_t uid)
-{
- if (uid < REGULAR_UID_MIN) {
- snprintf(path_buf, size,
- "/run/aul/daemons/%d/.app-sock-%d", uid, pid);
- } else {
- snprintf(path_buf, size,
- "/run/aul/apps/%d/%d/.app-sock", uid, pid);
- }
-}
-
-static void __create_socket_link(const char *socket_path, int pid, uid_t uid)
-{
- char path[108];
-
- if (__create_socket_dir(pid, uid) < 0)
- return;
-
- __create_socket_path(path, sizeof(path), pid, uid);
- if (link(socket_path, path) < 0) {
- if (errno == EEXIST)
- _D("path(%s) - already exists", path);
- else
- _E("path(%s) - unknown create error", path);
- }
-
- snprintf(socket_link_path, sizeof(socket_link_path), "%s", path);
- socket_link_created = 1;
-}
-
-API int aul_sock_create_server(int pid, uid_t uid)
-{
- struct sockaddr_un saddr;
- int fd;
- int env_pid = -1;
- char *env_str;
-
- fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- /* support above version 2.6.27*/
- if (fd < 0) {
- if (errno == EINVAL) {
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- _E("second chance - socket create error");
- return -1;
- }
- } else {
- _E("socket error");
- return -1;
- }
- }
-
- memset(&saddr, 0, sizeof(saddr));
- saddr.sun_family = AF_UNIX;
-
- if (__create_socket_dir(pid, uid) < 0) {
- close(fd);
- return -1;
- }
-
- __create_socket_path(saddr.sun_path, sizeof(saddr.sun_path), pid, uid);
- unlink(saddr.sun_path);
-
- /* labeling to socket for SMACK */
- if (getuid() == 0) { /* this is meaningful if current user is ROOT */
- if (fsetxattr(fd, "security.SMACK64IPOUT", "@", 1, 0) < 0) {
- /* in case of unsupported filesystem on 'socket' */
- /* or permission error by using 'emulator', bypass*/
- if ((errno != EOPNOTSUPP) && (errno != EPERM)) {
- _E("labeling to socket(IPOUT) error");
- close(fd);
- return -1;
- }
- }
- if (fsetxattr(fd, "security.SMACK64IPIN", "*", 1, 0) < 0) {
- /* in case of unsupported filesystem on 'socket' */
- /* or permission error by using 'emulator', bypass*/
- if ((errno != EOPNOTSUPP) && (errno != EPERM)) {
- _E("labeling to socket(IPIN) error");
- close(fd);
- return -1;
- }
- }
- }
-
- if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
- _E("bind error");
- close(fd);
- return -1;
- }
-
- aul_sock_set_sock_option(fd, 0);
-
- if (listen(fd, 128) == -1) {
- _E("listen error");
- close(fd);
- return -1;
- }
-
- /* Create socket link */
- if (pid > 0) {
- env_str = getenv("AUL_PID");
- if (env_str && isdigit(env_str[0]))
- env_pid = atoi(env_str);
-
- if (env_pid > 1 && pid != env_pid)
- __create_socket_link(saddr.sun_path, env_pid, uid);
- }
-
- return fd;
-}
-
-static int __create_client_sock(int pid, uid_t uid)
-{
- int fd = -1;
- struct sockaddr_un saddr = { 0, };
- int retry = 2;
- int ret = -1;
-
- fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- /* support above version 2.6.27*/
- if (fd < 0) {
- if (errno == EINVAL) {
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- _E("second chance - socket create error");
- return -1;
- }
- } else {
- _E("socket error");
- return -1;
- }
- }
-
- saddr.sun_family = AF_UNIX;
- if (pid == AUL_UTIL_PID) {
- snprintf(saddr.sun_path, sizeof(saddr.sun_path),
- "%s", PATH_AMD_SOCK);
- } else {
- __create_socket_path(saddr.sun_path, sizeof(saddr.sun_path), pid, uid);
- }
-
-retry_con:
- ret = __connect_client_sock(fd, (struct sockaddr *)&saddr, sizeof(saddr),
- 100 * 1000);
- if (ret < -1) {
- _E("maybe peer not launched or peer(%d:%u) dead. fd(%d)",
- pid, uid, fd);
- if (retry > 0) {
- usleep(100 * 1000);
- retry--;
- goto retry_con;
- }
- }
-
- if (ret < 0) {
- _E("Failed to connect the socket. fd(%d), errno(%d)",
- fd, errno);
- close(fd);
- return -1;
- }
-
- aul_sock_set_sock_option(fd, 1);
-
- return fd;
-}
-
-static int __connect_client_sock(int fd, const struct sockaddr *saptr, socklen_t salen,
- int nsec)
-{
- int flags;
- int ret;
- int error = 0;
- socklen_t len;
- fd_set readfds;
- fd_set writefds;
- struct timeval timeout;
-
- flags = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-
- ret = connect(fd, (struct sockaddr *)saptr, salen);
- if (ret < 0) {
- if (errno != EAGAIN && errno != EINPROGRESS) {
- (void)fcntl(fd, F_SETFL, flags);
- return -2;
- }
- }
-
- /* Do whatever we want while the connect is taking place. */
- if (ret == 0)
- goto done; /* connect completed immediately */
-
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
- writefds = readfds;
- timeout.tv_sec = 0;
- timeout.tv_usec = nsec;
-
- ret = select(fd + 1, &readfds, &writefds, NULL, nsec ? &timeout : NULL);
- if (ret == 0) {
- errno = ETIMEDOUT;
- return -1;
- }
-
- if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
- len = sizeof(error);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
- return -1; /* Solaris pending error */
- }
-
- return -1; /* select error: sockfd not set*/
-
-done:
- ret = fcntl(fd, F_SETFL, flags);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int __send_raw_async_with_fd(int fd, int cmd, unsigned char *kb_data, int datalen, int opt)
-{
- int len;
- int sent = 0;
- app_pkt_t *pkt = NULL;
-
- pkt = (app_pkt_t *)calloc(1, sizeof(app_pkt_t) + datalen);
- if (NULL == pkt) {
- _E("Malloc Failed!");
- return -ENOMEM;
- }
-
- pkt->cmd = cmd;
- pkt->len = datalen;
- pkt->opt = opt;
-
- if (kb_data)
- memcpy(pkt->data, kb_data, pkt->len);
-
- while (sent != AUL_PKT_HEADER_SIZE + pkt->len) {
- len = send(fd, (char *)pkt + sent,
- AUL_PKT_HEADER_SIZE + pkt->len - sent,
- MSG_NOSIGNAL);
- if (len <= 0) {
- _E("send error fd:%d (errno %d)", fd, errno);
- free(pkt);
- return -ECOMM;
- }
- sent += len;
- }
-
- free(pkt);
-
- return 0;
-}
-
-API int aul_sock_send_raw_with_fd(int fd, int cmd, unsigned char *kb_data, int datalen, int opt)
-{
- int len;
- int res;
-
- _D("fd(%d): cmd(%d)", fd, cmd);
-
- res = __send_raw_async_with_fd(fd, cmd, kb_data, datalen, opt);
- if (res < 0 || opt & AUL_SOCK_NOREPLY) {
- if (!(opt & AUL_SOCK_ASYNC))
- close(fd);
- return res;
- }
-
- if (opt & AUL_SOCK_ASYNC)
- return fd;
-
- len = __recv_raw(fd, (unsigned char *)&res, sizeof(int));
- if (len < 0)
- res = len;
-
- close(fd);
-
- return res;
-}
-
-API int aul_sock_send_bundle_with_fd(int fd, int cmd, bundle *kb, int opt)
-{
- bundle_raw *kb_data = NULL;
- int datalen;
- int res;
-
- if (!kb)
- return -EINVAL;
-
- res = bundle_encode(kb, &kb_data, &datalen);
- if (res != BUNDLE_ERROR_NONE)
- return -EINVAL;
-
- res = aul_sock_send_raw_with_fd(fd, cmd, kb_data, datalen, opt | AUL_SOCK_BUNDLE);
-
- if (kb_data)
- free(kb_data);
-
- return res;
-}
-
-/*
- * @brief Send data (in raw) to the process with 'pid' via socket
- */
-API int aul_sock_send_raw(int pid, uid_t uid, int cmd,
- unsigned char *kb_data, int datalen, int opt)
-{
- int fd;
- int r;
-
- _D("pid(%d): cmd(%d)", pid, cmd);
-
- fd = __create_client_sock(pid, uid);
- if (fd < 0)
- return -ECOMM;
-
- r = aul_sock_send_raw_with_fd(fd, cmd, kb_data, datalen, opt);
- if (r < 0) {
- if (opt & AUL_SOCK_ASYNC)
- close(fd);
- }
-
- return r;
-}
-
-API int aul_sock_send_bundle(int pid, uid_t uid, int cmd, bundle *kb, int opt)
-{
- bundle_raw *kb_data = NULL;
- int datalen;
- int res;
-
- if (!kb)
- return -EINVAL;
-
- res = bundle_encode(kb, &kb_data, &datalen);
- if (res != BUNDLE_ERROR_NONE)
- return -EINVAL;
-
- res = aul_sock_send_raw(pid, uid, cmd, kb_data, datalen, opt | AUL_SOCK_BUNDLE);
-
- if (kb_data)
- free(kb_data);
-
- return res;
-}
-
-API app_pkt_t *aul_sock_recv_pkt(int fd, int *clifd, struct ucred *cr)
-{
- struct sockaddr_un aul_addr = { 0, };
- int sun_size = sizeof(struct sockaddr_un);
- int cl = sizeof(struct ucred);
- app_pkt_t *pkt = NULL;
- int client_fd;
- int ret;
-
- client_fd = accept(fd, (struct sockaddr *)&aul_addr,
- (socklen_t *)&sun_size);
- if (client_fd == -1) {
- if (errno != EINTR)
- _E("accept error");
- return NULL;
- }
-
- ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED,
- cr, (socklen_t *)&cl);
- if (ret < 0) {
- _E("peer information error");
- close(client_fd);
- return NULL;
- }
-
- aul_sock_set_sock_option(client_fd, 1);
-
- ret = __recv_pkt(client_fd, &pkt);
- if (ret < 0) {
- close(client_fd);
- return NULL;
- }
-
- *clifd = client_fd;
-
- return pkt;
-}
-
-API int aul_sock_recv_reply_pkt(int fd, app_pkt_t **ret_pkt)
-{
- return aul_sock_recv_reply_pkt_v2(fd, ret_pkt, true);
-}
-
-static int __get_descriptors(struct cmsghdr *cmsg, struct msghdr *msg, int *fds, int maxdesc)
-{
- int retnr = 0;
- int nrdesc;
- int payload;
- int *recvdesc;
- int i;
-
- if (cmsg == NULL || msg == NULL)
- return 0;
- if (cmsg->cmsg_type != SCM_RIGHTS)
- return 0;
-
- if (msg->msg_controllen > 0) {
- payload = cmsg->cmsg_len - sizeof(*cmsg);
- recvdesc = (int *)CMSG_DATA(cmsg);
-
- nrdesc = payload / sizeof(int);
- retnr = nrdesc < maxdesc ? nrdesc : maxdesc;
- for (i = 0; i < nrdesc; ++i) {
- if (maxdesc-- > 0)
- *fds++ = *recvdesc++;
- else
- close(*recvdesc++);
- }
- }
-
- return retnr;
-}
-
-static int __recv_message(int sock, struct iovec *vec, int vec_max_size, int *vec_size,
- int *fds, int *nr_fds)
-{
- char buff[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS) + CMSG_SPACE(50)] = {0};
- struct msghdr msg = {0};
- struct cmsghdr *cmsg = NULL;
- bool is_blocking;
- int ret;
-
- if (vec == NULL || vec_max_size < 1 || vec_size == NULL)
- return -EINVAL;
-
- msg.msg_iov = vec;
- msg.msg_iovlen = vec_max_size;
- msg.msg_control = buff;
- msg.msg_controllen = sizeof(buff);
-
- if (fcntl(sock, F_GETFL, 0) & O_NONBLOCK)
- is_blocking = false;
- else
- is_blocking = true;
-
-retry:
- ret = recvmsg(sock, &msg, 0);
- if (ret == 0) {
- _W("Socket was disconnected. fd(%d)", sock);
- return -ECOMM;
- } else if (ret < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- if (is_blocking && errno == EAGAIN) {
- _E("recvmsg timeout. fd(%d)", sock);
- return -EAGAIN;
- }
-
- goto retry;
- }
-
- ret = -errno;
- _E("recvmsg error. fd(%d), errno(%d)", sock, errno);
- return ret;
- }
-
- *vec_size = msg.msg_iovlen;
-
- /* get the ANCILLARY data */
- cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg == NULL) {
- if (nr_fds != NULL)
- *nr_fds = 0;
- } else {
- int iter = 0;
- int fdnum = 0;
-
- for (; cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg), iter++) {
- switch (cmsg->cmsg_type) {
- case SCM_RIGHTS:
- if (fds != NULL)
- fdnum = __get_descriptors(cmsg, &msg, fds, MAX_NR_OF_DESCRIPTORS);
- if (nr_fds != NULL)
- *nr_fds = fdnum;
- break;
- }
- }
- }
-
- return 0;
-}
-
-int aul_sock_recv_reply_sock_fd(int fd, int (*ret_fd)[2], int fd_size)
-{
- int fds[2] = {0,};
- char recv_buff[1024];
- struct iovec vec[3];
- int ret = 0;
- int vec_len = 0;
- int fds_len = 0;
-
- vec[0].iov_base = recv_buff;
- vec[0].iov_len = sizeof(recv_buff);
- ret = __recv_message(fd, vec, 1, &vec_len, fds, &fds_len);
- if (ret < 0) {
- _E("Error[%d]. while receiving message", -ret);
- if (fds_len > 0)
- close(fds[0]);
-
- ret = -ECOMM;
- } else if ((fds_len == fd_size) && (fds_len == 2)) {
- (*ret_fd)[0] = fds[0];
- (*ret_fd)[1] = fds[1];
- } else if ((fds_len == fd_size) && (fds_len == 1)) {
- (*ret_fd)[0] = fds[0];
- } else {
- _E("wrong number of FD recevied. Expected:%d Actual:%d", fd_size, fds_len);
- ret = -ECOMM;
- }
-
- close(fd);
- return ret;
-}
-
-int aul_sock_create_launchpad_client(const char *pad_type, uid_t uid)
-{
- int fd = -1;
- struct sockaddr_un saddr = { 0, };
- int retry = 1;
- int ret = -1;
-
- fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- /* support above version 2.6.27*/
- if (fd < 0) {
- if (errno == EINVAL) {
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- _E("second chance - socket create error");
- return -1;
- }
- } else {
- _E("socket error");
- return -1;
- }
- }
-
- saddr.sun_family = AF_UNIX;
- snprintf(saddr.sun_path, sizeof(saddr.sun_path),
- "/run/aul/daemons/%d/%s", uid, pad_type);
-retry_con:
- ret = __connect_client_sock(fd, (struct sockaddr *)&saddr,
- sizeof(saddr), 100 * 1000);
- if (ret < -1) {
- _E("maybe peer not launched or peer dead");
- if (retry > 0) {
- usleep(100 * 1000);
- retry--;
- goto retry_con;
- }
- }
- if (ret < 0) {
- close(fd);
- return -1;
- }
-
- aul_sock_set_sock_option(fd, 1);
-
- return fd;
-}
-
-API int aul_sock_recv_pkt_with_cb(int fd,
- void (*callback)(app_pkt_t *pkt, void *data),
- void *user_data)
-{
- app_pkt_t **pkt;
- int count = 0;
- size_t size;
- int ret;
- int i;
-
- if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
- _E("Invalid parameter");
- return -1;
- }
-
- if (callback == NULL) {
- _E("Invalid parameter");
- close(fd);
- return -1;
- }
-
- ret = __recv_raw(fd, (unsigned char *)&count, sizeof(int));
- if (ret < 0) {
- _E("recv error - %d", ret);
- close(fd);
- return ret;
- } else if (count <= 0 || count > MAX_RUNNING_INSTANCE) {
- _E("error - count: %d", count);
- close(fd);
- return -ECOMM;
- }
-
- size = sizeof(app_pkt_t *) * count;
- _D("count: %d, size: %zu", count, size);
- pkt = (app_pkt_t **)calloc(1, size);
- if (pkt == NULL) {
- _E("out of memory");
- close(fd);
- return -1;
- }
-
- for (i = 0; i < count; ++i) {
- ret = __recv_pkt(fd, &pkt[i]);
- if (ret < 0) {
- _E("Failed to receive packet");
- break;
- }
- }
-
- for (i = 0; i < count; ++i) {
- callback(pkt[i], user_data);
- free(pkt[i]);
- }
-
- free(pkt);
- close(fd);
-
- return ret;
-}
-
-API int aul_sock_recv_result_with_fd(int fd)
-{
- int len;
- int res;
-
- len = __recv_raw(fd, (unsigned char *)&res, sizeof(int));
- if (len < 0) {
- _E("Failed to receive the result. fd(%d)", fd);
- res = -ECOMM;
- }
-
- return res;
-}
-
-static void __delete_dir(const char *path)
-{
- DIR *dp;
- struct dirent *dentry = NULL;
- char buf[PATH_MAX];
- struct stat statbuf;
- int ret;
-
- if (path == NULL)
- return;
-
- dp = opendir(path);
- if (dp == NULL)
- return;
-
- while ((dentry = readdir(dp)) != NULL) {
- if (!strcmp(dentry->d_name, ".") ||
- !strcmp(dentry->d_name, ".."))
- continue;
-
- snprintf(buf, sizeof(buf), "%s/%s", path, dentry->d_name);
- ret = stat(buf, &statbuf);
- if (ret == 0) {
- if (S_ISDIR(statbuf.st_mode))
- __delete_dir(buf);
- else
- unlink(buf);
- }
- }
-
- rmdir(path);
- closedir(dp);
-}
-
-API int aul_sock_destroy_server(int fd)
-{
- char path[PATH_MAX];
-
- if (fd > 3)
- close(fd);
-
- if (getuid() >= REGULAR_UID_MIN) {
- snprintf(path, sizeof(path),
- "/run/aul/apps/%u/%d",
- getuid(), getpid());
- __delete_dir(path);
-
- if (socket_link_created) {
- __delete_dir(dirname(socket_link_path));
- socket_link_created = 0;
- }
- } else {
- snprintf(path, sizeof(path),
- "/run/aul/daemons/%u/.app-sock-%d",
- getuid(), getpid());
- unlink(path);
-
- if (socket_link_created) {
- unlink(socket_link_path);
- socket_link_created = 0;
- }
- }
-
- return 0;
-}
-
-API int aul_sock_send_result(int fd, int res)
-{
- return aul_sock_send_result_v2(fd, res, true);
-}
-
-API int aul_sock_send_result_v2(int fd, int res, bool do_close)
-{
- int ret;
-
- if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- ret = send(fd, &res, sizeof(res), MSG_NOSIGNAL);
- if (ret < 0)
- _E("Failed to send result. fd(%d), errno(%d)", fd, errno);
-
- if (do_close)
- close(fd);
-
- return ret;
-}
-
-API int aul_sock_recv_reply_pkt_v2(int fd, app_pkt_t **pkt, bool do_close)
-{
- int ret;
-
- if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX))
- return -EINVAL;
-
- if (!pkt) {
- if (do_close)
- close(fd);
- return -EINVAL;
- }
-
- ret = __recv_pkt(fd, pkt);
- if (do_close)
- close(fd);
-
- return ret;
-}
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/aul_sock.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <tzplatform_config.h>
+#include <unistd.h>
+#include <vconf.h>
+
+#include <bundle_cpp.h>
+
+#include "aul_api.h"
+#include "aul_util.h"
+
+#include "aul/socket/client_socket.hh"
+#include "aul/socket/packet.hh"
+#include "aul/socket/server_socket.hh"
+
+using namespace aul;
+
+namespace {
+
+constexpr const int MAX_NR_OF_DESCRIPTORS = 2;
+constexpr const int MAX_PAYLOAD_SIZE = 1024 * 1024 * 1;
+constexpr const char PATH_AUL_SOCKET_TIMEOUT[] = "/run/aul/.socket_timeout";
+constexpr const char PATH_AMD_SOCK[] = "/run/aul/daemons/.amd-sock";
+int MAX_FDS = sysconf(_SC_OPEN_MAX);
+
+// POD type
+struct PacketHeader {
+ int cmd;
+ int len;
+ int opt;
+};
+
+class SocketTimeout {
+ public:
+ SocketTimeout() = default;
+
+ ~SocketTimeout() {
+ if (initialized_)
+ vconf_ignore_key_changed(VCONFKEY_AUL_SOCKET_TIMEOUT, VconfCb);
+ }
+
+ timeval GetTimeval() const {
+ return time_val_;
+ }
+
+ bool IsInitialized() const {
+ return initialized_;
+ }
+
+ void Init() {
+ if (access(PATH_AUL_SOCKET_TIMEOUT, F_OK) != 0) {
+ initialized_ = true;
+ return;
+ }
+
+ double timeout = 5.2f;
+ int ret = vconf_get_dbl(VCONFKEY_AUL_SOCKET_TIMEOUT, &timeout);
+ if (ret != VCONF_OK)
+ _E("vconf_get_dbl() is failed. error(%d)", ret);
+
+ ret = vconf_notify_key_changed(VCONFKEY_AUL_SOCKET_TIMEOUT, VconfCb, this);
+ if (ret != VCONF_OK)
+ _E("vconf_notify_key_changed() is failed. error(%d)", ret);
+
+ SetTimeout(timeout);
+ initialized_ = true;
+ }
+
+ private:
+ static void VconfCb(keynode_t* node, void* user_data) {
+ auto* h = static_cast<SocketTimeout*>(user_data);
+ double timeout = vconf_keynode_get_dbl(node);
+ h->SetTimeout(timeout);
+ }
+
+ void SetTimeout(double timeout) {
+ char buf[12];
+ snprintf(buf, sizeof(buf), "%.3f", timeout);
+ gchar* ptr = nullptr;
+ time_val_.tv_sec = g_ascii_strtoll(buf, &ptr, 10);
+ time_val_.tv_usec = g_ascii_strtoll(ptr + 1, &ptr, 10) * 1000;
+ }
+
+ private:
+ bool initialized_ = false;
+ timeval time_val_ = { 5, 200 * 1000 };
+};
+
+std::string GetSocketPath(pid_t pid, uid_t uid) {
+ if (pid == -2)
+ return std::string(PATH_AMD_SOCK);
+
+ char path[108];
+ if (uid < REGULAR_UID_MIN)
+ snprintf(path, sizeof(path), "/run/aul/daemons/%u/.app-sock-%d", uid, pid);
+ else
+ snprintf(path, sizeof(path), "/run/aul/apps/%u/%d/.app-sock", uid, pid);
+
+ return std::string(path);
+}
+
+int CreateSocketDirectory(pid_t pid, uid_t uid) {
+ std::string socket_path = GetSocketPath(pid, uid);
+ std::string path = dirname(const_cast<char*>(socket_path.c_str()));
+ if (mkdir(path.c_str(), 0700) != 0) {
+ if (errno == EEXIST) {
+ if (access(path.c_str(), R_OK) != 0) {
+ _E("access() is failed. path(%s), errno(%d)", path.c_str(), errno);
+ return -1;
+ }
+ } else {
+ _E("mkdir() is failed. path(%s), errno(%d)", path.c_str(), errno);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+class SocketLink {
+ public:
+ SocketLink() = default;
+
+ void Create(const std::string& socket_path, pid_t pid, uid_t uid) {
+ if (CreateSocketDirectory(pid, uid) != 0)
+ return;
+
+ path_ = GetSocketPath(pid, uid);
+ if (link(socket_path.c_str(), path_.c_str()) != 0) {
+ _E("link() is failed. old(%s), new(%s), errno(%d)",
+ socket_path.c_str(), path_.c_str(), errno);
+ }
+
+ created_ = true;
+ }
+
+ void Delete() {
+ if (!created_)
+ return;
+
+ unlink(path_.c_str());
+ created_ = false;
+ }
+
+ private:
+ bool created_ = false;
+ std::string path_;
+};
+
+int SendAndReceive(ClientSocket* client, int cmd, unsigned char* data,
+ int datalen, int opt) {
+ _D("fd(%d), cmd(%d)", client->GetFd(), cmd);
+
+ Packet packet(cmd, opt, { data, data + datalen });
+ tizen_base::Parcel parcel;
+ parcel.WriteParcelable(packet);
+ auto raw = parcel.GetRaw();
+
+ int ret = client->Send(reinterpret_cast<void*>(&raw[0]), raw.size());
+ if (ret != 0 || opt & AUL_SOCK_NOREPLY) {
+ if (opt & AUL_SOCK_ASYNC)
+ client->RemoveFd();
+
+ return ret;
+ }
+
+ if (opt & AUL_SOCK_ASYNC)
+ return client->RemoveFd();
+
+ int res;
+ ret = client->Receive(reinterpret_cast<void*>(&res), sizeof(res));
+ if (ret < 0)
+ res = ret;
+
+ return res;
+}
+
+int SendAndReceive(int fd, int cmd, unsigned char* data, int datalen,
+ int opt) {
+ ClientSocket client(fd);
+ return SendAndReceive(&client, cmd, data, datalen, opt);
+}
+
+int SendAndReceive(int pid, uid_t uid, int cmd, unsigned char* data,
+ int datalen, int opt) {
+ int ret;
+ try {
+ ClientSocket client;
+ std::string endpoint = GetSocketPath(pid, uid);
+ client.Connect(endpoint);
+ aul_sock_set_sock_option(client.GetFd(), 1);
+
+ ret = SendAndReceive(&client, cmd, data, datalen, opt);
+ } catch (const Exception& e) {
+ _E("Exception occurs. error(%d)", e.GetErrorCode());
+ return e.GetErrorCode();
+ }
+
+ return ret;
+}
+
+int ReceiveAppPacket(ClientSocket* client, app_pkt_t** out_pkt) {
+ PacketHeader header;
+ static_assert(std::is_standard_layout<PacketHeader>(),
+ "PacketHeader should be POD type");
+ static_assert(std::is_trivial<PacketHeader>(),
+ "Header should be POD type");
+
+ *out_pkt = nullptr;
+ int ret = client->Receive(&header, sizeof(header));
+ if (ret < 0)
+ return ret;
+
+ app_pkt_t* pkt = static_cast<app_pkt_t*>(
+ calloc(1, sizeof(app_pkt_t) + header.len));
+ if (pkt == nullptr) {
+ _E("Out of memory");
+ return -ENOMEM;
+ }
+
+ pkt->cmd = header.cmd;
+ pkt->len = header.len;
+ pkt->opt = header.opt;
+
+ ret = client->Receive(pkt->data, pkt->len);
+ if (ret < 0) {
+ free(pkt);
+ return ret;
+ }
+
+ *out_pkt = pkt;
+ return 0;
+}
+
+int GetFileDescriptor(struct cmsghdr* cmsg, struct msghdr* msg, int* fds,
+ int maxdesc) {
+ if (cmsg == nullptr || msg == nullptr)
+ return 0;
+
+ if (cmsg->cmsg_type != SCM_RIGHTS)
+ return 0;
+
+ int retnr = 0;
+ if (msg->msg_controllen > 0) {
+ int payload = cmsg->cmsg_len - sizeof(*cmsg);
+ int* recvdesc = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ int nrdesc = payload / sizeof(int);
+ retnr = nrdesc < maxdesc ? nrdesc : maxdesc;
+ for (int i = 0; i < nrdesc; ++i) {
+ if (maxdesc-- > 0)
+ *fds++ = *recvdesc++;
+ else
+ close(*recvdesc++);
+ }
+ }
+
+ return retnr;
+}
+
+int ReceiveMessage(int fd, struct iovec* vec, int vec_max_size, int* vec_size,
+ int* fds, int* nr_fds) {
+ if (vec == nullptr || vec_max_size < 1 || vec_size == nullptr)
+ return -EINVAL;
+
+ char buf[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS) + CMSG_SPACE(50)] = { 0, };
+ struct msghdr msg = { 0, };
+ msg.msg_iov = vec;
+ msg.msg_iovlen = vec_max_size;
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+
+ bool is_blocking;
+ if (fcntl(fd, F_GETFL, 0) & O_NONBLOCK)
+ is_blocking = false;
+ else
+ is_blocking = true;
+
+retry:
+ int ret = recvmsg(fd, &msg, 0);
+ if (ret == 0) {
+ _W("Socket was disconnected. fd(%d)", fd);
+ return -ECOMM;
+ }
+
+ if (ret < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ if (is_blocking && errno == EAGAIN) {
+ _E("recvmsg() timed out. fd(%d)", fd);
+ return -EAGAIN;
+ }
+
+ usleep(100 * 1000);
+ goto retry;
+ }
+
+ ret = -errno;
+ _E("recvmsg() is failed. fd(%d), errno(%d)", fd, errno);
+ return ret;
+ }
+
+ *vec_size = msg.msg_iovlen;
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == nullptr) {
+ if (nr_fds != nullptr)
+ *nr_fds = 0;
+ } else {
+ for (int i = 0; cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg), ++i) {
+ if (cmsg->cmsg_type == SCM_RIGHTS) {
+ if (fds != nullptr) {
+ int fdnum = GetFileDescriptor(cmsg, &msg, fds, MAX_NR_OF_DESCRIPTORS);
+ if (nr_fds != nullptr)
+ *nr_fds = fdnum;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void DeleteDirectories(const std::string& path) {
+ if (path.empty())
+ return;
+
+ DIR* dp = opendir(path.c_str());
+ if (dp == nullptr)
+ return;
+
+ struct stat statbuf;
+ struct dirent* dentry = nullptr;
+ while ((dentry = readdir(dp)) != nullptr) {
+ if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
+ continue;
+
+ std::string entry = path + dentry->d_name;
+ if (stat(entry.c_str(), &statbuf) == 0) {
+ if (S_ISDIR(statbuf.st_mode))
+ DeleteDirectories(entry);
+ else
+ unlink(entry.c_str());
+ }
+ }
+
+ rmdir(path.c_str());
+ closedir(dp);
+}
+
+SocketTimeout socket_timeout;
+SocketLink socket_link;
+
+} // namespace
+
+extern "C" API struct timeval aul_sock_get_rcv_timeout(void) {
+ return socket_timeout.GetTimeval();
+}
+
+extern "C" API int aul_sock_set_sock_option(int fd, int cli) {
+ int size = AUL_SOCK_MAXBUFF;
+ int ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+ if (ret != 0)
+ return ret;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+ if (ret != 0)
+ return ret;
+
+ if (cli) {
+ if (TIZEN_FEATURE_SOCKET_TIMEOUT && !socket_timeout.IsInitialized())
+ socket_timeout.Init();
+
+ auto timeout = socket_timeout.GetTimeval();
+ ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+extern "C" API int aul_sock_create_server(int pid, uid_t uid) {
+ auto path = GetSocketPath(pid, uid);
+ int fd = -1;
+ try {
+ if (CreateSocketDirectory(pid, uid) != 0)
+ return -1;
+
+ ServerSocket socket;
+ socket.Bind(path);
+ aul_sock_set_sock_option(socket.GetFd(), 0);
+ socket.Listen(128);
+ fd = socket.RemoveFd();
+ } catch (const Exception& e) {
+ _E("Exception occurs. error(%d)", e.GetErrorCode());
+ return e.GetErrorCode();
+ }
+
+ if (pid > 0) {
+ pid_t aul_pid;
+ const char* aul_pid_str = getenv("AUL_PID");
+ if (aul_pid_str != nullptr && isdigit(aul_pid_str[0]))
+ aul_pid = atoi(aul_pid_str);
+ else
+ aul_pid = -1;
+
+ if (aul_pid > 1 && aul_pid != pid)
+ socket_link.Create(path.c_str(), aul_pid, uid);
+ }
+
+ return fd;
+}
+
+extern "C" API int aul_sock_send_raw_with_fd(int fd, int cmd,
+ unsigned char* kb_data, int datalen, int opt) {
+ return SendAndReceive(fd, cmd, kb_data, datalen, opt);
+}
+
+extern "C" API int aul_sock_send_bundle_with_fd(int fd, int cmd, bundle* kb,
+ int opt) {
+ if (kb == nullptr)
+ return -EINVAL;
+
+ tizen_base::Bundle b(kb, false, false);
+ auto raw = b.ToRaw();
+ return SendAndReceive(fd, cmd,
+ reinterpret_cast<unsigned char*>(raw.first.get()),
+ raw.second, opt | AUL_SOCK_BUNDLE);
+}
+
+extern "C" API int aul_sock_send_raw(int pid, uid_t uid, int cmd,
+ unsigned char* kb_data, int datalen, int opt) {
+ return SendAndReceive(pid, uid, cmd, kb_data, datalen, opt);
+}
+
+extern "C" API int aul_sock_send_bundle(int pid, uid_t uid, int cmd,
+ bundle* kb, int opt) {
+ if (kb == nullptr)
+ return -EINVAL;
+
+ tizen_base::Bundle b(kb, false, false);
+ auto raw = b.ToRaw();
+ return SendAndReceive(pid, uid, cmd,
+ reinterpret_cast<unsigned char*>(raw.first.get()), raw.second,
+ opt | AUL_SOCK_BUNDLE);
+}
+
+extern "C" API app_pkt_t* aul_sock_recv_pkt(int fd, int* clifd,
+ struct ucred* cred) {
+ ServerSocket server(fd);
+ auto client = std::unique_ptr<ClientSocket>(server.Accept());
+ server.RemoveFd();
+ if (client.get() == nullptr)
+ return nullptr;
+
+ socklen_t optlen = sizeof(struct ucred);
+ int ret = getsockopt(client->GetFd(), SOL_SOCKET, SO_PEERCRED,
+ cred, &optlen);
+ if (ret < 0) {
+ _E("getsockopt() is failed. errno(%d)", errno);
+ return nullptr;
+ }
+
+ aul_sock_set_sock_option(client->GetFd(), 1);
+
+ app_pkt_t* pkt = nullptr;
+ ret = ReceiveAppPacket(client.get(), &pkt);
+ if (ret < 0)
+ return nullptr;
+
+ *clifd = client->RemoveFd();
+ return pkt;
+}
+
+extern "C" API int aul_sock_recv_reply_pkt(int fd, app_pkt_t** ret_pkt) {
+ return aul_sock_recv_reply_pkt_v2(fd, ret_pkt, true);
+}
+
+extern "C" API int aul_sock_recv_reply_sock_fd(int fd, int (*ret_fd)[2],
+ int fd_size) {
+ int fds[2] = { -1, -1 };
+ int vec_len = 0;
+ int fds_len = 0;
+ char recv_buff[1024] = { 0, };;
+ struct iovec vec[3] = { 0, };
+ vec[0].iov_base = recv_buff;
+ vec[0].iov_len = sizeof(recv_buff);
+ int ret = ReceiveMessage(fd, vec, 1, &vec_len, fds, &fds_len);
+ if (ret < 0) {
+ _E("ReceiveMessage() is failed. error(%d)", ret);
+ if (fds_len > 0)
+ close(fds[0]);
+
+ ret = -ECOMM;
+ } else if (fds_len == fd_size && fds_len == 2) {
+ (*ret_fd)[0] = fds[0];
+ (*ret_fd)[1] = fds[1];
+ } else if (fds_len == fd_size && fds_len == 1) {
+ (*ret_fd)[0] = fds[0];
+ } else {
+ _E("Wrong number of FD received. Expected: %d, Actual: %d",
+ fd_size, fds_len);
+ ret = -ECOMM;
+ }
+
+ close(fd);
+ return ret;
+}
+
+extern "C" API int aul_sock_create_launchpad_client(const char* pad_type,
+ uid_t uid) {
+ int fd = -1;
+ try {
+ ClientSocket client;
+ std::string endpoint = "/run/aul/daemons/" + std::to_string(uid) + "/" +
+ std::string(pad_type);
+ client.Connect(endpoint);
+ fd = client.RemoveFd();
+ aul_sock_set_sock_option(fd, 1);
+ } catch (const Exception& e) {
+ _E("Exception occurs. error(%d)", e.GetErrorCode());
+ return e.GetErrorCode();
+ }
+
+ return fd;
+}
+
+extern "C" API int aul_sock_recv_pkt_with_cb(int fd,
+ void (*callback)(app_pkt_t* pkt, void* user_data),
+ void* user_data) {
+ if (fd < 0 || fd >= MAX_FDS) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ if (callback == nullptr) {
+ _E("Invalid parameter");
+ close(fd);
+ return -1;
+ }
+
+ ClientSocket client(fd);
+ int count = 0;
+ int ret = client.Receive(&count, sizeof(count));
+ if (ret != 0) {
+ _E("Receive() is failed. error(%d)", ret);
+ return ret;
+ }
+
+ if (count <= 0 || count > MAX_RUNNING_INSTANCE) {
+ _E("Error occurs. count(%d)", count);
+ return -ECOMM;
+ }
+
+ app_pkt_t** pkt = reinterpret_cast<app_pkt_t**>(
+ calloc(count, sizeof(app_pkt_t*)));
+ if (pkt == nullptr) {
+ _E("Out of memory");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < count; ++i) {
+ ret = ReceiveAppPacket(&client, &pkt[i]);
+ if (ret != 0) {
+ _E("ReceiveAppPacket() is failed. error(%d)", ret);
+ break;
+ }
+ }
+
+ for (int i = 0; i < count; ++i) {
+ if (pkt[i] != nullptr) {
+ callback(pkt[i], user_data);
+ free(pkt[i]);
+ }
+ }
+
+ free(pkt);
+ return ret;
+}
+
+extern "C" API int aul_sock_recv_result_with_fd(int fd) {
+ ClientSocket client(fd);
+ int res;
+ int ret = client.Receive(&res, sizeof(res));
+ client.RemoveFd();
+ if (ret < 0) {
+ _E("Receive() is failed. fd(%d), error(%d)", fd, ret);
+ res = -ECOMM;
+ }
+
+ return res;
+}
+
+extern "C" API int aul_sock_destroy_server(int fd) {
+ if (fd > -1)
+ close(fd);
+
+ if (getuid() < REGULAR_UID_MIN) {
+ std::string path = "/run/aul/daemons/" + std::to_string(getuid()) +
+ "/.app-sock-" + std::to_string(getpid());
+ unlink(path.c_str());
+ } else {
+ std::string path = "/run/aul/apps/" + std::to_string(getuid()) + "/" +
+ std::to_string(getpid());
+ DeleteDirectories(path);
+ }
+ socket_link.Delete();
+
+ return 0;
+}
+
+extern "C" API int aul_sock_send_result(int fd, int res) {
+ return aul_sock_send_result_v2(fd, res, true);
+}
+
+extern "C" API int aul_sock_send_result_v2(int fd, int res, bool do_close) {
+ if (fd < 0 || fd >= MAX_FDS) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ int ret = send(fd, &res, sizeof(res), MSG_NOSIGNAL);
+ if (ret < 0)
+ _E("send() is failed. fd(%d), errno(%d)", fd, errno);
+
+ if (do_close)
+ close(fd);
+
+ return ret;
+}
+
+extern "C" API int aul_sock_recv_reply_pkt_v2(int fd, app_pkt_t** pkt,
+ bool do_close) {
+ if (fd < 0 || fd >= MAX_FDS)
+ return -EINVAL;
+
+ if (pkt == nullptr) {
+ if (do_close)
+ close(fd);
+
+ return -EINVAL;
+ }
+
+ ClientSocket client(fd);
+ int ret = ReceiveAppPacket(&client, pkt);
+ if (!do_close)
+ client.RemoveFd();
+
+ return ret;
+}
#include <gtest/gtest.h>
#include <gmock/gmock.h>
-//#define LOG_INTERNAL
-
#include <dlog.h>
-extern "C" int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...) {
-#ifdef LOG_INTERNAL
+extern "C" int __dlog_print(log_id_t log_id, int prio, const char* tag,
+ const char* fmt, ...) {
printf("%s:", tag);
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
-#endif
return 0;
}