Modify ClientSocket implementation 63/315363/6
authorHwankyu Jhun <h.jhun@samsung.com>
Wed, 31 Jul 2024 01:43:15 +0000 (10:43 +0900)
committerHwanKyu Jhun <h.jhun@samsung.com>
Wed, 31 Jul 2024 05:17:30 +0000 (05:17 +0000)
- Adds Send() and Receive() methods for sending the parcelable instance
- Uses recv() instead of read()
- Adds exception handlings about EAGAIN error
- Adds the retrying count for error handling

Change-Id: I41dd952d6fa90500a30f0193f0e8fe747675b462
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/rpc-port/client-socket-internal.cc
src/rpc-port/client-socket-internal.hh
src/rpc-port/proxy-internal.cc
src/rpc-port/request-internal.cc
src/rpc-port/request-internal.hh
src/rpc-port/response-internal.cc
src/rpc-port/response-internal.hh
src/rpc-port/stub-internal.cc

index 9a71b4efa74a8e74596b1514385d643e8056d20f..c982e3150784c6d12f9f4f9e030edda875c6eea5 100644 (file)
  * limitations under the License.
  */
 
+#include "rpc-port/client-socket-internal.hh"
+
 #include <errno.h>
 #include <fcntl.h>
+#include <glib-unix.h>
 #include <limits.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <unistd.h>
 
-#include "client-socket-internal.hh"
-#include "exception-internal.hh"
-#include "log-private.hh"
+#include "rpc-port/exception-internal.hh"
+#include "rpc-port/log-private.hh"
+
+namespace {
+
+const int kMaxRetryingCount = 10;
+
+class TemporaryBlockingMode {
+ public:
+  explicit TemporaryBlockingMode(int fd) : fd_(fd) {
+    g_unix_set_fd_nonblocking(fd_, false, nullptr);
+  }
+
+  ~TemporaryBlockingMode() { g_unix_set_fd_nonblocking(fd_, true, nullptr); }
+
+ private:
+  int fd_;
+};
+
+}  // namespace
 
 namespace rpc_port {
 namespace internal {
 
 ClientSocket::ClientSocket() {
   fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
-  if (fd_ < 0) {
-    // LCOV_EXCL_START
+  if (fd_ < 0) {  // LCOV_EXCL_START
     fd_ = -errno;
     _E("socket() is failed. errno(%d)", errno);
     THROW(fd_);
-    // LCOV_EXCL_STOP
-  }
+  }  // LCOV_EXCL_STOP
 }
 
-ClientSocket::ClientSocket(int fd) : fd_(fd) {
-  SetCloseOnExec();
-}
+ClientSocket::ClientSocket(int fd) : fd_(fd) { SetCloseOnExec(); }
 
 ClientSocket::~ClientSocket() {
-  if (!IsClosed())
-    Close();
+  if (!IsClosed()) Close();
 }
 
 void ClientSocket::SetCloseOnExec() {
@@ -72,31 +87,46 @@ int ClientSocket::Connect(const std::string& endpoint) {
       endpoint.c_str());
   struct sockaddr* sockaddr_ptr = reinterpret_cast<struct sockaddr*>(&sockaddr);
   socklen_t len = static_cast<socklen_t>(sizeof(sockaddr));
-  int ret = connect(GetFd(), sockaddr_ptr, len);
-  fcntl(GetFd(), F_SETFL, flag);
-  if (ret < 0) {
-    // LCOV_EXCL_START
+
+  int ret;
+  int retrying_count = 2;
+  do {
+    ret = connect(GetFd(), sockaddr_ptr, len);
+    if (ret == 0) break;
+
+    retrying_count--;
     ret = -errno;
+    usleep(100 * 1000);
+  } while (retrying_count > 0);
+
+  fcntl(GetFd(), F_SETFL, flag);
+  if (ret < 0) {  // LCOV_EXCL_START
     _E("connect() is failed. errno(%d)", errno);
     return ret;
-    // LCOV_EXCL_STOP
-  }
+  }  // LCOV_EXCL_STOP
 
   return 0;
 }
 
 int ClientSocket::Send(const void* buf, unsigned int size) {
+  int retrying_count = kMaxRetryingCount;
   const unsigned char* buffer = static_cast<const unsigned char*>(buf);
   size_t len = size;
   while (len) {
     ssize_t bytes = send(GetFd(), buffer, len, MSG_NOSIGNAL);
-    if (bytes < 0) {
-      // LCOV_EXCL_START
+    if (bytes < 0) {  // LCOV_EXCL_START
+      if (errno == EINTR || errno == EAGAIN) {
+        if (retrying_count > 0) {
+          retrying_count--;
+          usleep(10 * 1000);
+          continue;
+        }
+      }
+
       int ret = -errno;
       _E("send() is failed. fd(%d), errno(%d)", GetFd(), errno);
       return ret;
-      // LCOV_EXCL_STOP
-    }
+    }  // LCOV_EXCL_STOP
 
     len -= bytes;
     buffer += bytes;
@@ -106,23 +136,27 @@ int ClientSocket::Send(const void* buf, unsigned int size) {
 }
 
 int ClientSocket::Receive(void* buf, unsigned int size) {
+  int retyring_count = kMaxRetryingCount;
   unsigned char* buffer = static_cast<unsigned char*>(buf);
   size_t len = size;
   while (len) {
-    ssize_t bytes = read(GetFd(), buffer, len);
-    if (bytes == 0) {
-      _W("EOF. fd(%d)", GetFd());  // LCOV_EXCL_START
-      return -EIO;  // LCOV_EXCL_STOP
-    }
-
-    if (bytes < 0) {
-      if (errno == EINTR) {
-        usleep(100 * 1000);
-        continue;
+    ssize_t bytes = recv(GetFd(), buffer, len, 0);
+    if (bytes == 0) {  // LCOV_EXCL_START
+      _W("EOF. fd(%d)", GetFd());
+      return -EIO;
+    }  // LCOV_EXCL_STOP
+
+    if (bytes < 0) {  // LCOV_EXCL_START
+      if (errno == EINTR || errno == EAGAIN) {
+        if (retyring_count > 0) {
+          retyring_count--;
+          usleep(100 * 1000);
+          continue;
+        }
       }
 
-      return -errno;  // LCOV_EXCL_LINE
-    }
+      return -errno;
+    }  // LCOV_EXCL_STOP
 
     len -= bytes;
     buffer += bytes;
@@ -132,16 +166,15 @@ int ClientSocket::Receive(void* buf, unsigned int size) {
 }
 
 void ClientSocket::SetReceiveTimeout(int timeout) {
-  if (timeout == INT_MAX)
-    return;  // LCOV_EXCL_LINE
+  if (timeout == INT_MAX) return;  // LCOV_EXCL_LINE
 
   if (timeout == -1)
     timeout = 5000;
 
-  if (timeout < 0) {
-    _E("Invalid parameter");  // LCOV_EXCL_LINE
-    THROW(-EINVAL);  // LCOV_EXCL_LINE
-  }
+  if (timeout < 0) {  // LCOV_EXCL_START
+    _E("Invalid parameter");
+    THROW(-EINVAL);
+  }  // LCOV_EXCL_STOP
 
   struct timeval tv = {
     .tv_sec = static_cast<time_t>(timeout / 1000),
@@ -149,22 +182,16 @@ void ClientSocket::SetReceiveTimeout(int timeout) {
   };
   socklen_t len = static_cast<socklen_t>(sizeof(struct timeval));
   int ret = setsockopt(GetFd(), SOL_SOCKET, SO_RCVTIMEO, &tv, len);
-  if (ret < 0) {
-    // LCOV_EXCL_START
+  if (ret < 0) {  // LCOV_EXCL_START
     ret = -errno;
     _E("setsockopt() is failed. errno(%d)", errno);
     THROW(ret);
-    // LCOV_EXCL_STOP
-  }
+  }  // LCOV_EXCL_STOP
 }
 
-bool ClientSocket::IsClosed() {
-  return fd_ < 0 ? true : false;
-}
+bool ClientSocket::IsClosed() { return fd_ < 0; }
 
-int ClientSocket::GetFd() const {
-  return fd_;
-}
+int ClientSocket::GetFd() const { return fd_; }
 
 int ClientSocket::RemoveFd() {
   int fd = fd_;
@@ -172,9 +199,34 @@ int ClientSocket::RemoveFd() {
   return fd;
 }
 
-void ClientSocket::SetNonblock() {
-  int flag = fcntl(GetFd(), F_GETFL, 0);
-  fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK);
+void ClientSocket::SetNonblock(bool nonblock) {
+  g_unix_set_fd_nonblocking(fd_, nonblock, nullptr);
+}
+
+int ClientSocket::Send(const tizen_base::Parcelable& parcelable) {
+  TemporaryBlockingMode mode(GetFd());
+  tizen_base::Parcel parcel;
+  parcel.WriteParcelable(parcelable);
+  size_t size = parcel.GetDataSize();
+  int ret = Send(reinterpret_cast<void*>(&size), sizeof(size));
+  if (ret != 0) return ret;
+
+  return Send(parcel.GetData(), size);
+}
+
+int ClientSocket::Receive(tizen_base::Parcelable* parcelable) {
+  TemporaryBlockingMode mode(GetFd());
+  size_t size = 0;
+  int ret = Receive(reinterpret_cast<void*>(&size), sizeof(size));
+  if (ret != 0) return ret;
+
+  std::vector<uint8_t> data(size);
+  ret = Receive(data.data(), size);
+  if (ret != 0) return ret;
+
+  tizen_base::Parcel parcel(data.data(), data.size(), true);
+  parcel.ReadParcelable(parcelable);
+  return ret;
 }
 
 }  // namespace internal
index d033b2ef409d68d0b3997cb3576997da949effc4..9548b43b9173d47bc85abbc8c56740283b1486a9 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <string>
 
+#include <parcel.hh>
+
 namespace rpc_port {
 namespace internal {
 
@@ -36,9 +38,12 @@ class ClientSocket {
   bool IsClosed();
   int GetFd() const;
   int RemoveFd();
-  void SetNonblock();
+  void SetNonblock(bool nonblock = true);
   void SetCloseOnExec();
 
+  int Send(const tizen_base::Parcelable& parcelable);
+  int Receive(tizen_base::Parcelable* parcelable);
+
  private:
   int fd_;
 };
index 4058aca3d47b37a15873cff735cd25c9c70cdcf2..ce4dcc8c2a7411cdb0305b0f0083d67526b4513c 100644 (file)
@@ -53,86 +53,6 @@ std::string GenInstance() {
   return std::string(uuid) + "@" + Aul::GetAppId(getpid());
 }
 
-int SendRequest(ClientSocket* client, const Request& request) {
-  tizen_base::Parcel parcel;
-  parcel.WriteParcelable(const_cast<Request&>(request));
-  size_t size = parcel.GetDataSize();
-  int ret = client->Send(reinterpret_cast<void*>(&size), sizeof(size));
-  if (ret != 0) {
-    // LCOV_EXCL_START
-    _E("Send() is failed. error(%d)", ret);
-    return -1;
-    // LCOV_EXCL_STOP
-  }
-
-  ret = client->Send(parcel.GetData(), size);
-  if (ret != 0) {
-    // LCOV_EXCL_START
-    _E("Send() is failed. error(%d)", ret);
-    return -1;
-    // LCOV_EXCL_STOP
-  }
-
-  return 0;
-}
-
-int ReceiveResponse(ClientSocket* client, Response** response) {
-  int flags = fcntl(client->GetFd(), F_GETFL, 0);
-  fcntl(client->GetFd(), F_SETFL, flags & ~O_NONBLOCK);
-
-  size_t size = 0;
-  int ret = client->Receive(reinterpret_cast<void*>(&size), sizeof(size));
-  if (ret != 0) {
-    // LCOV_EXCL_START
-    _E("Receive() is failed. error(%d)", ret);
-    fcntl(client->GetFd(), F_SETFL, flags);
-    return -1;
-    // LCOV_EXCL_STOP
-  }
-
-  uint8_t* buf = static_cast<uint8_t*>(malloc(size));
-  if (buf == nullptr) {
-    // LCOV_EXCL_START
-    _E("Out of memory");
-    fcntl(client->GetFd(), F_SETFL, flags);
-    return -1;
-    // LCOV_EXCL_STOP
-  }
-
-  ret = client->Receive(buf, size);
-  if (ret != 0) {
-    // LCOV_EXCL_START
-    _E("Receive() is failed. error(%d)", ret);
-    free(buf);
-    fcntl(client->GetFd(), F_SETFL, flags);
-    return -1;
-    // LCOV_EXCL_STOP
-  }
-
-  tizen_base::Parcel parcel(buf, size, false);
-  *response = new (std::nothrow) Response();
-  if (*response == nullptr) {
-    // LCOV_EXCL_START
-    _E("Out of memory");
-    fcntl(client->GetFd(), F_SETFL, flags);
-    return -1;
-    // LCOV_EXCL_STOP
-  }
-
-  parcel.ReadParcelable(*response);
-  fcntl(client->GetFd(), F_SETFL, flags);
-  return 0;
-}
-
-int ReceiveResult(ClientSocket* client) {
-  Response* response = nullptr;
-  int ret = ReceiveResponse(client, &response);
-  if (ret != 0) return ret;
-
-  std::unique_ptr<Response> response_auto(response);
-  return response->GetResult();
-}
-
 bool IsDaemon(const std::string& name) {
   if (name.compare(0, strlen(kDPrefix), kDPrefix) == 0) return true;
 
@@ -169,17 +89,16 @@ int Proxy::MainPortConnect(const std::string& instance, bool sync) {
     return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
 
   Request request(instance.c_str(), kPortTypeMain);
-  int ret = SendRequest(main_client_.get(), request);
+  int ret = main_client_->Send(request);
   if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
 
   main_client_->SetNonblock();
   if (sync) {
-    Response* response = nullptr;
-    ret = ReceiveResponse(main_client_.get(), &response);
+    Response response;
+    ret = main_client_->Receive(&response);
     if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
 
-    std::unique_ptr<Response> response_auto(response);
-    if (response->GetResult() != 0) {
+    if (response.GetResult() != 0) {
       // LCOV_EXCL_START
       _E("Permission denied");
       return RPC_PORT_ERROR_PERMISSION_DENIED;
@@ -203,17 +122,16 @@ int Proxy::DelegatePortConnect(const std::string& instance, bool sync) {
     return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
 
   Request request(instance.c_str(), kPortTypeDelegate);
-  int ret = SendRequest(delegate_client_.get(), request);
+  int ret = delegate_client_->Send(request);
   if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
 
   delegate_client_->SetNonblock();
   if (sync) {
-    Response* response = nullptr;
-    ret = ReceiveResponse(delegate_client_.get(), &response);
+    Response response;
+    ret = delegate_client_->Receive(&response);
     if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
 
-    std::unique_ptr<Response> response_auto(response);
-    if (response->GetResult() != 0) {
+    if (response.GetResult() != 0) {
       // LCOV_EXCL_START
       _E("Permission denied");
       return RPC_PORT_ERROR_PERMISSION_DENIED;
@@ -698,7 +616,9 @@ void Proxy::OnResponseReceived(int fd) {
     // LCOV_EXCL_STOP
   }
 
-  if (ReceiveResult(client.get()) != 0) {
+  Response response;
+  int ret = client->Receive(&response);
+  if (ret != 0 || response.GetResult() != 0) {
     _E("Permission denied");
     auto* listener = listener_;
     listener_ = nullptr;
index c293c29a6d0c4abb96e98693b9064a11966d6bfe..93bbcec398153c1fb32bb98285632d9b3dc4c7f9 100644 (file)
@@ -22,21 +22,15 @@ namespace rpc_port {
 namespace internal {
 
 Request::Request(std::string instance, std::string port_type)
-    : instance_(std::move(instance)),
-      port_type_(std::move(port_type)) {
-}
+    : instance_(std::move(instance)), port_type_(std::move(port_type)) {}
 
 void Request::SetPortType(std::string port_type) {
   port_type_ = std::move(port_type);
 }
 
-const std::string& Request::GetInstance() {
-  return instance_;
-}
+const std::string& Request::GetInstance() const { return instance_; }
 
-const std::string& Request::GetPortType() {
-  return port_type_;
-}
+const std::string& Request::GetPortType() const { return port_type_; }
 
 void Request::WriteToParcel(tizen_base::Parcel* parcel) const {
   parcel->WriteString(instance_);
index 3aa9b05816d85daf87a928f7c71c00df528ec071..8f40c16160b540750746a7c7846f659c07dd347d 100644 (file)
@@ -32,8 +32,8 @@ class Request : public tizen_base::Parcelable {
   ~Request() = default;
 
   void SetPortType(std::string port_type);
-  const std::string& GetInstance();
-  const std::string& GetPortType();
+  const std::string& GetInstance() const;
+  const std::string& GetPortType() const;
 
   void WriteToParcel(tizen_base::Parcel* parcel) const override;
   void ReadFromParcel(tizen_base::Parcel* parcel) override;
index 9d32604bed2546b8e5772336353b5ba01eabde56..1d3102faed46cd1b0e183e087601dce336a29581 100644 (file)
 namespace rpc_port {
 namespace internal {
 
-Response::Response(int result) : result_(result) {
-}
+Response::Response(int result) : result_(result) {}
 
-Response::Response() : result_(0) {
-}
+Response::Response() : result_(0) {}
 
-int Response::GetResult() {
-  return result_;
-}
+int Response::GetResult() const { return result_; }
 
 void Response::WriteToParcel(tizen_base::Parcel* parcel) const {
   parcel->WriteInt32(result_);
index 2c12ab29f9e8f02c6958fb1553c9e02d9798680f..ac802726778d392e82f09266390e4eddc4994cd5 100644 (file)
@@ -29,7 +29,7 @@ class Response : public tizen_base::Parcelable {
   Response();
   ~Response() = default;
 
-  int GetResult();
+  int GetResult() const;
 
   void WriteToParcel(tizen_base::Parcel* parcel) const override;
   void ReadFromParcel(tizen_base::Parcel* parcel) override;
index aa2cecf71fa5763dd979f9fb18f0bf395f7baf3c..22f1060ac4d0ac33a2d090d5bbcfc7b58bd39d00 100644 (file)
@@ -44,51 +44,6 @@ constexpr const char kPortTypeMain[] = "main";
 constexpr const char kPortTypeDelegate[] = "delegate";
 constexpr uid_t kRegularUidMin = 5000;
 
-int ReceiveRequest(ClientSocket* client, Request** request) {
-  size_t size = 0;
-  int ret = client->Receive(reinterpret_cast<void*>(&size), sizeof(size));
-  if (ret != 0) {
-    _E("Receive() is failed. error(%d)", ret);  // LCOV_EXCL_LINE
-    return -1;  // LCOV_EXCL_LINE
-  }
-
-  std::vector<uint8_t> buf(size);
-  ret = client->Receive(buf.data(), size);
-  if (ret != 0) {
-    _E("Receive() is failed. error(%d)", ret);  // LCOV_EXCL_LINE
-    return -1;  // LCOV_EXCL_LINE
-  }
-
-  tizen_base::Parcel parcel(buf.data(), buf.size());
-  *request = new (std::nothrow) Request();
-  if (*request == nullptr) {
-    _E("Out of memory");  // LCOV_EXCL_LINE
-    return -1;  // LCOV_EXCL_LINE
-  }
-
-  parcel.ReadParcelable(*request);
-  return 0;
-}
-
-int SendResponse(ClientSocket* client, const Response& response) {
-  tizen_base::Parcel parcel;
-  parcel.WriteParcelable(const_cast<Response&>(response));
-  size_t size = parcel.GetDataSize();
-  int ret = client->Send(reinterpret_cast<void*>(&size), sizeof(size));
-  if (ret != 0) {
-    _E("Send() is failed. error(%d)", ret);  // LCOV_EXCL_LINE
-    return -1;  // LCOV_EXCL_LINE
-  }
-
-  ret = client->Send(parcel.GetData(), size);
-  if (ret != 0) {
-    _E("Send() is failed. error(%d)", ret);  // LCOV_EXCL_LINE
-    return -1;  // LCOV_EXCL_LINE
-  }
-
-  return 0;
-}
-
 }  // namespace
 
 std::unordered_set<Stub*> Stub::freed_stubs_;
@@ -343,7 +298,7 @@ void Stub::CheckPermission(const std::shared_ptr<Request>& request,
     if (pending_request_count_ != 0) pending_request_count_--;
 
     Response response(res);
-    int ret = SendResponse(client.get(), response);
+    int ret = client->Send(response);
     if (ret != 0) return;  // LCOV_EXCL_LINE
 
     if (res != 0) {
@@ -397,11 +352,10 @@ void Stub::OnRequestReceived(gint fd) {
     // LCOV_EXCL_STOP
   }
 
-  Request* request = nullptr;
-  int ret = ReceiveRequest(client.get(), &request);
+  auto request = std::make_shared<Request>();
+  int ret = client->Receive(request.get());
   if (ret != 0) return;  // LCOV_EXCL_LINE
 
-  std::shared_ptr<Request> request_auto(request);
   std::shared_ptr<PeerCred> cred(PeerCred::Get(client->GetFd()));
   if (!cred) {
     // LCOV_EXCL_START
@@ -410,7 +364,7 @@ void Stub::OnRequestReceived(gint fd) {
     // LCOV_EXCL_STOP
   }
 
-  CheckPermission(request_auto, client, cred);
+  CheckPermission(request, client, cred);
 }
 
 }  // namespace internal