Change the send Buffer size dynamically

On a Linux system the send buffer size has defaulted
to around 90k, and when a pldm message is sent via
the pldm_send() that is bigger than 90k, we get an error
ENOBUFS (No buffer space avilable).

This commit would dynamically change the socket parameter
(SO_SNDBUF) to set the new maximum socket send buffer size
so that we can successfully send the message.

Tested By:

1. hard coded the current buffer size value to 10 and forced
   the buffer size to be increase for mutiple commands & was able
   to power on the host with out any problems.

Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: I5f7a3948ea019b4dc983cf5e1926cfc128c02084
diff --git a/requester/handler.hpp b/requester/handler.hpp
index 6290526..ff7f33d 100644
--- a/requester/handler.hpp
+++ b/requester/handler.hpp
@@ -9,6 +9,8 @@
 #include "pldmd/dbus_impl_requester.hpp"
 #include "request.hpp"
 
+#include <sys/socket.h>
+
 #include <function2/function2.hpp>
 #include <sdbusplus/timer.hpp>
 #include <sdeventplus/event.hpp>
@@ -91,6 +93,7 @@
      *  @param[in] fd - fd of MCTP communications socket
      *  @param[in] event - reference to PLDM daemon's main event loop
      *  @param[in] requester - reference to Requester object
+     *  @param[in] currentSendbuffSize - current send buffer size
      *  @param[in] verbose - verbose tracing flag
      *  @param[in] instanceIdExpiryInterval - instance ID expiration interval
      *  @param[in] numRetries - number of request retries
@@ -98,14 +101,15 @@
      */
     explicit Handler(
         int fd, sdeventplus::Event& event, pldm::dbus_api::Requester& requester,
-        bool verbose,
+        int currentSendbuffSize, bool verbose,
         std::chrono::seconds instanceIdExpiryInterval =
             std::chrono::seconds(INSTANCE_ID_EXPIRATION_INTERVAL),
         uint8_t numRetries = static_cast<uint8_t>(NUMBER_OF_REQUEST_RETRIES),
         std::chrono::milliseconds responseTimeOut =
             std::chrono::milliseconds(RESPONSE_TIME_OUT)) :
         fd(fd),
-        event(event), requester(requester), verbose(verbose),
+        event(event), requester(requester),
+        currentSendbuffSize(currentSendbuffSize), verbose(verbose),
         instanceIdExpiryInterval(instanceIdExpiryInterval),
         numRetries(numRetries), responseTimeOut(responseTimeOut)
     {}
@@ -165,7 +169,7 @@
 
         auto request = std::make_unique<RequestInterface>(
             fd, eid, event, std::move(requestMsg), numRetries, responseTimeOut,
-            verbose);
+            currentSendbuffSize, verbose);
         auto timer = std::make_unique<phosphor::Timer>(
             event.get(), instanceIdExpiryCallBack);
 
@@ -240,6 +244,7 @@
     int fd; //!< file descriptor of MCTP communications socket
     sdeventplus::Event& event; //!< reference to PLDM daemon's main event loop
     pldm::dbus_api::Requester& requester; //!< reference to Requester object
+    int currentSendbuffSize;              //!< current Send Buffer size
     bool verbose;                         //!< verbose tracing flag
     std::chrono::seconds
         instanceIdExpiryInterval; //!< Instance ID expiration interval
diff --git a/requester/request.hpp b/requester/request.hpp
index 24e6942..2f2470f 100644
--- a/requester/request.hpp
+++ b/requester/request.hpp
@@ -6,6 +6,8 @@
 #include "common/types.hpp"
 #include "common/utils.hpp"
 
+#include <sys/socket.h>
+
 #include <sdbusplus/timer.hpp>
 #include <sdeventplus/event.hpp>
 
@@ -141,6 +143,7 @@
      *
      *  @param[in] fd - fd of the MCTP communication socket
      *  @param[in] eid - endpoint ID of the remote MCTP endpoint
+     *  @param[in] currrentSendbuffSize - the current send buffer size
      *  @param[in] event - reference to PLDM daemon's main event loop
      *  @param[in] requestMsg - PLDM request message
      *  @param[in] numRetries - number of request retries
@@ -149,16 +152,19 @@
      */
     explicit Request(int fd, mctp_eid_t eid, sdeventplus::Event& event,
                      pldm::Request&& requestMsg, uint8_t numRetries,
-                     std::chrono::milliseconds timeout, bool verbose) :
+                     std::chrono::milliseconds timeout, int currentSendbuffSize,
+                     bool verbose) :
         RequestRetryTimer(event, numRetries, timeout),
-        fd(fd), eid(eid), requestMsg(std::move(requestMsg)), verbose(verbose)
+        fd(fd), eid(eid), requestMsg(std::move(requestMsg)),
+        currentSendbuffSize(currentSendbuffSize), verbose(verbose)
     {}
 
   private:
     int fd;                   //!< file descriptor of MCTP communications socket
     mctp_eid_t eid;           //!< endpoint ID of the remote MCTP endpoint
     pldm::Request requestMsg; //!< PLDM request message
-    bool verbose;             //!< verbose tracing flag
+    mutable int currentSendbuffSize; //!< current Send Buffer size
+    bool verbose;                    //!< verbose tracing flag
 
     /** @brief Sends the PLDM request message on the socket
      *
@@ -170,6 +176,24 @@
         {
             pldm::utils::printBuffer(pldm::utils::Tx, requestMsg);
         }
+        if (currentSendbuffSize >= 0 &&
+            (size_t)currentSendbuffSize < requestMsg.size())
+        {
+            int oldSendbuffSize = currentSendbuffSize;
+            currentSendbuffSize = requestMsg.size();
+            int res =
+                setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &currentSendbuffSize,
+                           sizeof(currentSendbuffSize));
+            if (res == -1)
+            {
+                std::cerr
+                    << "Requester : Failed to set the new send buffer size [bytes] : "
+                    << currentSendbuffSize
+                    << " from current size [bytes]: " << oldSendbuffSize
+                    << " , Error : " << strerror(errno) << std::endl;
+                return PLDM_ERROR;
+            }
+        }
         auto rc = pldm_send(eid, fd, requestMsg.data(), requestMsg.size());
         if (rc < 0)
         {
diff --git a/requester/test/handler_test.cpp b/requester/test/handler_test.cpp
index 144e5f5..068aff0 100644
--- a/requester/test/handler_test.cpp
+++ b/requester/test/handler_test.cpp
@@ -74,8 +74,8 @@
 
 TEST_F(HandlerTest, singleRequestResponseScenario)
 {
-    Handler<NiceMock<MockRequest>> reqHandler(fd, event, dbusImplReq, false,
-                                              seconds(1), 2, milliseconds(100));
+    Handler<NiceMock<MockRequest>> reqHandler(
+        fd, event, dbusImplReq, false, 90000, seconds(1), 2, milliseconds(100));
     pldm::Request request{};
     auto instanceId = dbusImplReq.getInstanceId(eid);
     auto rc = reqHandler.registerRequest(
@@ -96,8 +96,8 @@
 
 TEST_F(HandlerTest, singleRequestInstanceIdTimerExpired)
 {
-    Handler<NiceMock<MockRequest>> reqHandler(fd, event, dbusImplReq, false,
-                                              seconds(1), 2, milliseconds(100));
+    Handler<NiceMock<MockRequest>> reqHandler(
+        fd, event, dbusImplReq, false, 90000, seconds(1), 2, milliseconds(100));
     pldm::Request request{};
     auto instanceId = dbusImplReq.getInstanceId(eid);
     auto rc = reqHandler.registerRequest(
@@ -116,8 +116,8 @@
 
 TEST_F(HandlerTest, multipleRequestResponseScenario)
 {
-    Handler<NiceMock<MockRequest>> reqHandler(fd, event, dbusImplReq, false,
-                                              seconds(2), 2, milliseconds(100));
+    Handler<NiceMock<MockRequest>> reqHandler(
+        fd, event, dbusImplReq, false, 90000, seconds(2), 2, milliseconds(100));
     pldm::Request request{};
     auto instanceId = dbusImplReq.getInstanceId(eid);
     auto rc = reqHandler.registerRequest(
@@ -150,4 +150,4 @@
     EXPECT_EQ(validResponse, true);
     EXPECT_EQ(callbackCount, 2);
     EXPECT_EQ(instanceId, dbusImplReq.getInstanceId(eid));
-}
\ No newline at end of file
+}
diff --git a/requester/test/mock_request.hpp b/requester/test/mock_request.hpp
index 355609d..7e6fc41 100644
--- a/requester/test/mock_request.hpp
+++ b/requester/test/mock_request.hpp
@@ -16,7 +16,8 @@
   public:
     MockRequest(int /*fd*/, mctp_eid_t /*eid*/, sdeventplus::Event& event,
                 pldm::Request&& /*requestMsg*/, uint8_t numRetries,
-                std::chrono::milliseconds responseTimeOut, bool /*verbose*/) :
+                std::chrono::milliseconds responseTimeOut,
+                int /*currentSendbuffSize*/, bool /*verbose*/) :
         RequestRetryTimer(event, numRetries, responseTimeOut)
     {}
 
@@ -25,4 +26,4 @@
 
 } // namespace requester
 
-} // namespace pldm
\ No newline at end of file
+} // namespace pldm
diff --git a/requester/test/request_test.cpp b/requester/test/request_test.cpp
index 5239c12..234ff32 100644
--- a/requester/test/request_test.cpp
+++ b/requester/test/request_test.cpp
@@ -49,7 +49,7 @@
 TEST_F(RequestIntfTest, 0Retries100msTimeout)
 {
     MockRequest request(fd, eid, event, std::move(requestMsg), 0,
-                        milliseconds(100), false);
+                        milliseconds(100), 90000, false);
     EXPECT_CALL(request, send())
         .Times(Exactly(1))
         .WillOnce(Return(PLDM_SUCCESS));
@@ -60,7 +60,7 @@
 TEST_F(RequestIntfTest, 2Retries100msTimeout)
 {
     MockRequest request(fd, eid, event, std::move(requestMsg), 2,
-                        milliseconds(100), false);
+                        milliseconds(100), 90000, false);
     // send() is called a total of 3 times, the original plus two retries
     EXPECT_CALL(request, send()).Times(3).WillRepeatedly(Return(PLDM_SUCCESS));
     auto rc = request.start();
@@ -71,7 +71,7 @@
 TEST_F(RequestIntfTest, 9Retries100msTimeoutRequestStoppedAfter1sec)
 {
     MockRequest request(fd, eid, event, std::move(requestMsg), 9,
-                        milliseconds(100), false);
+                        milliseconds(100), 90000, false);
     // send() will be called a total of 10 times, the original plus 9 retries.
     // In a ideal scenario send() would have been called 10 times in 1 sec (when
     // the timer is stopped) with a timeout of 100ms. Because there are delays
@@ -94,7 +94,7 @@
 TEST_F(RequestIntfTest, 2Retries100msTimeoutsendReturnsError)
 {
     MockRequest request(fd, eid, event, std::move(requestMsg), 2,
-                        milliseconds(100), false);
+                        milliseconds(100), 90000, false);
     EXPECT_CALL(request, send()).Times(Exactly(1)).WillOnce(Return(PLDM_ERROR));
     auto rc = request.start();
     EXPECT_EQ(rc, PLDM_ERROR);