* limitations under the License.
*/
+#include "client_socket.hh"
+
+#include <errno.h>
+#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <unistd.h>
-#include <algorithm>
-#include <string>
+#include "utils/logging.hh"
-#include "client_socket.hh"
+#include "pkgmgrinfo_debug.h"
+
+namespace {
+
+bool IsDBWriteRequest(pkgmgr_common::ReqType req_type) {
+ if (req_type != pkgmgr_common::ReqType::SET_PKG_INFO &&
+ req_type != pkgmgr_common::ReqType::SET_CERT_INFO &&
+ req_type != pkgmgr_common::ReqType::WRITE_QUERY)
+ return false;
+
+ return true;
+}
+
+}
namespace pkgmgr_common {
+namespace socket {
+
+ClientSocket::ClientSocket(std::string path)
+ : AbstractSocket(std::move(path)) {}
+
+void ClientSocket::SetTimeout(int timeout_msec) {
+ if (timeout_msec == -1)
+ timeout_msec = 5000;
-ClientSocket::ClientSocket(std::string path) : AbstractSocket(std::move(path)) {
- /* TODO implement code */
+ if (timeout_msec < 0) {
+ LOG(ERROR) << "Invalid timeout_msec parameter";
+ return;
+ }
+
+ struct timeval timeout = {
+ .tv_sec = static_cast<time_t>(timeout_msec / 1000),
+ .tv_usec = static_cast<suseconds_t>((timeout_msec % 1000) * 1000)};
+
+ if (setsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)
+ LOG(ERROR) << "setsockopt() is failed. fd: " << fd_
+ << ", errno: " << errno;
}
-ClientSocket::ClientSocket(int fd) : AbstractSocket(fd) {
- /* TODO implement code */
+bool ClientSocket::Connect(ReqType req_type) {
+ if (Create() < 0)
+ return false;
+
+ SetTimeout(IsDBWriteRequest(req_type) ? 60 * 1000 : 5 * 1000);
+
+ int retry_cnt = 3;
+ do {
+ int ret = TryConnection();
+ if (ret == 0) {
+ break;
+ } else if (ret < -1) {
+ LOG(ERROR) << "Maybe peer not launched or peer dead. path: " << GetPath()
+ << ", fd: " << GetFd();
+
+ // If requester is root, don't wait
+ if (getuid() == 0)
+ return false;
+
+ usleep(100 * 1000);
+ --retry_cnt;
+ } else if (ret < 0) {
+ LOG(ERROR) << "Failed to connect to socket: " << GetPath()
+ << ", fd: " << GetFd();
+ return false;
+ }
+ } while (retry_cnt > 0);
+
+ return (retry_cnt > 0);
}
-ClientSocket::~ClientSocket() { /* TODO implement code */ }
+int ClientSocket::TryConnection() {
+ int flags = fcntl(fd_, F_GETFL, 0);
+
+ if (fcntl(fd_, F_SETFL, flags | O_NONBLOCK) != 0) {
+ LOG(ERROR) << "Failed to set flags: " << (flags | O_NONBLOCK) << " on fd: "
+ << fd_ << ", errno: " << errno;
+ return -1;
+ }
+
+ int ret =
+ connect(fd_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_));
+ if (fcntl(fd_, F_SETFL, flags) != 0) {
+ LOG(ERROR) << "Failed to set flags: " << flags << " on fd: " << fd_
+ << ", errno: " << errno;
+ return -1;
+ }
+ if (ret < 0) {
+ if (errno != EAGAIN && errno != EINPROGRESS)
+ return -2;
+ } else if (ret == 0) {
+ SetOption();
+ return 0;
+ }
+
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(fd_, &readfds);
+ fd_set writefds = readfds;
+ struct timeval timeout = {0, 100 * 1000};
+ ret = select(fd_ + 1, &readfds, &writefds, NULL, &timeout);
+ if (ret == 0) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (FD_ISSET(fd_, &readfds) || FD_ISSET(fd_, &writefds)) {
+ int error = 0;
+ socklen_t len = sizeof(error);
+ if (getsockopt(fd_, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+ return -1;
+ }
-int ClientSocket::Connect() {
- /* TODO implement code */
- return 0;
+ return -1;
}
+} // namespace socket
} // namespace pkgmgr_common