From cff90c15fbea42b334611125d4f32fb18de24410 Mon Sep 17 00:00:00 2001 From: Adam Gu Date: Fri, 2 Jun 2017 17:22:40 +0800 Subject: [PATCH] Refine type convertion; add timeout handling. --- src/csoap/common.cc | 16 ++++++++++------ src/csoap/common.h | 19 +++---------------- src/csoap/http_client.cc | 36 +++++++++++++++++++++++++++++++++--- src/csoap/http_client.h | 9 +++++++++ src/demo/calculator.cc | 16 ++++++++-------- src/demo/calculator.h | 14 +++++++------- src/demo/main.cc | 6 +++--- 7 files changed, 73 insertions(+), 43 deletions(-) diff --git a/src/csoap/common.cc b/src/csoap/common.cc index 480904f..672804b 100644 --- a/src/csoap/common.cc +++ b/src/csoap/common.cc @@ -12,6 +12,9 @@ const char* GetErrorMessage(ErrorCode error_code) { case kEndpointConnectError: return "Cannot connect to remote endpoint."; + case kSocketTimeoutError: + return "Operation timeout."; + case kSocketReadError: return "Socket read error."; @@ -38,23 +41,24 @@ const char* GetErrorMessage(ErrorCode error_code) { //////////////////////////////////////////////////////////////////////////////// Parameter::Parameter(const std::string& key, const std::string& value) - : key_(key) { - value_ = LexicalCast(value, ""); + : key_(key), value_(value) { } Parameter::Parameter(const std::string& key, int value) : key_(key) { - value_ = LexicalCast(value, ""); + value_ = boost::lexical_cast(value); } -Parameter::Parameter(const std::string& key, float value) +Parameter::Parameter(const std::string& key, double value) : key_(key) { - value_ = LexicalCast(value, ""); + char buf[32]; + sprintf(buf, "%f", value); + value_ = buf; } Parameter::Parameter(const std::string& key, bool value) : key_(key) { - value_ = LexicalCast(value, ""); + value_ = value ? "true" : "false"; } } // namespace csoap diff --git a/src/csoap/common.h b/src/csoap/common.h index 9e3632d..a93ef9a 100644 --- a/src/csoap/common.h +++ b/src/csoap/common.h @@ -10,27 +10,14 @@ namespace csoap { //////////////////////////////////////////////////////////////////////////////// -// Wrapper for boost::lexcical_cast. -// Usage: -// LexicalCast("123", 0); -// LexicalCast(123, ""); -template -To LexicalCast(const From& input, const To& default_output) { - try { - return boost::lexical_cast(input); - } catch (boost::bad_lexical_cast&) { - return default_output; - } -} - -//////////////////////////////////////////////////////////////////////////////// - enum ErrorCode { kNoError = 0, // OK kHostResolveError, kEndpointConnectError, + kSocketTimeoutError, + kSocketReadError, kSocketWriteError, @@ -66,7 +53,7 @@ class Parameter { public: Parameter(const std::string& key, const std::string& value); Parameter(const std::string& key, int value); - Parameter(const std::string& key, float value); + Parameter(const std::string& key, double value); Parameter(const std::string& key, bool value); const char* c_key() const { diff --git a/src/csoap/http_client.cc b/src/csoap/http_client.cc index 03c2ab3..5cc0794 100644 --- a/src/csoap/http_client.cc +++ b/src/csoap/http_client.cc @@ -61,7 +61,7 @@ void HttpRequest::ToString(std::string& req_string) const { req_string += kFieldContentLengthName; req_string += ": "; - req_string += LexicalCast(content_length_, "0"); + req_string += boost::lexical_cast(content_length_); req_string += kCRLF; req_string += "SOAPAction: "; @@ -220,7 +220,8 @@ void HttpResponse::ParseContentLength(const std::string& line) { //////////////////////////////////////////////////////////////////////////////// -HttpClient::HttpClient() { +HttpClient::HttpClient() + : timeout_seconds_(15) { } ErrorCode HttpClient::SendRequest(const HttpRequest& request, @@ -254,6 +255,8 @@ ErrorCode HttpClient::SendRequest(const HttpRequest& request, return kEndpointConnectError; } + SetTimeout(socket); + std::string request_str; request.ToString(request_str); @@ -272,7 +275,11 @@ ErrorCode HttpClient::SendRequest(const HttpRequest& request, size_t len = socket.read_some(boost::asio::buffer(bytes_), ec); if (len == 0 || ec) { - return kSocketReadError; + if (ec.value() == WSAETIMEDOUT) { + return kSocketTimeoutError; + } else { + return kSocketReadError; + } } // Parse the response piece just read. @@ -288,4 +295,27 @@ ErrorCode HttpClient::SendRequest(const HttpRequest& request, return kNoError; } +// See https://stackoverflow.com/a/9079092 +void HttpClient::SetTimeout(boost::asio::ip::tcp::socket& socket) { +#if defined _WINDOWS + + int ms = timeout_seconds_ * 1000; + + const char* optval = reinterpret_cast(&ms); + size_t optlen = sizeof(ms); + + setsockopt(socket.native(), SOL_SOCKET, SO_RCVTIMEO, optval, optlen); + setsockopt(socket.native(), SOL_SOCKET, SO_SNDTIMEO, optval, optlen); + +#else // POSIX + + struct timeval tv; + tv.tv_sec = timeout_seconds_; + tv.tv_usec = 0; + setsockopt(socket.native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(socket.native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + +#endif +} + } // namespace csoap diff --git a/src/csoap/http_client.h b/src/csoap/http_client.h index c5b7f08..55b46cb 100644 --- a/src/csoap/http_client.h +++ b/src/csoap/http_client.h @@ -145,13 +145,22 @@ class HttpClient { public: HttpClient(); + // Set socket send & recv timeout. + void set_timeout_seconds(int seconds) { + timeout_seconds_ = seconds; + } + ErrorCode SendRequest(const HttpRequest& request, const std::string& body, HttpResponse* response); +private: + void SetTimeout(boost::asio::ip::tcp::socket& socket); + private: boost::asio::io_service io_service_; std::array bytes_; + int timeout_seconds_; }; } // namespace csoap diff --git a/src/demo/calculator.cc b/src/demo/calculator.cc index 4760fb9..b41106b 100644 --- a/src/demo/calculator.cc +++ b/src/demo/calculator.cc @@ -10,19 +10,19 @@ Calculator::Calculator() { Init(); } -bool Calculator::Add(float x, float y, float* result) { +bool Calculator::Add(double x, double y, double* result) { return Calc("add", "x", "y", x, y, result); } -bool Calculator::Subtract(float x, float y, float* result) { +bool Calculator::Subtract(double x, double y, double* result) { return Calc("subtract", "x", "y", x, y, result); } -bool Calculator::Multiply(float x, float y, float* result) { +bool Calculator::Multiply(double x, double y, double* result) { return Calc("multiply", "x", "y", x, y, result); } -bool Calculator::Divide(float x, float y, float* result) { +bool Calculator::Divide(double x, double y, double* result) { return Calc("divide", "numerator", "denominator", x, y, result); } @@ -38,9 +38,9 @@ void Calculator::Init() { bool Calculator::Calc(const std::string& operation, const std::string& x_name, const std::string& y_name, - float x, - float y, - float* result) { + double x, + double y, + double* result) { csoap::Parameter parameters[] = { { x_name, x }, { y_name, y } @@ -52,7 +52,7 @@ bool Calculator::Calc(const std::string& operation, } try { - *result = boost::lexical_cast(result_str); + *result = boost::lexical_cast(result_str); } catch (boost::bad_lexical_cast&) { return false; } diff --git a/src/demo/calculator.h b/src/demo/calculator.h index 0650cb4..2353b02 100644 --- a/src/demo/calculator.h +++ b/src/demo/calculator.h @@ -13,13 +13,13 @@ class Calculator { public: Calculator(); - bool Add(float x, float y, float* result); + bool Add(double x, double y, double* result); - bool Subtract(float x, float y, float* result); + bool Subtract(double x, double y, double* result); - bool Multiply(float x, float y, float* result); + bool Multiply(double x, double y, double* result); - bool Divide(float x, float y, float* result); + bool Divide(double x, double y, double* result); protected: void Init(); @@ -28,9 +28,9 @@ protected: bool Calc(const std::string& operation, const std::string& x_name, const std::string& y_name, - float x, - float y, - float* result); + double x, + double y, + double* result); // A generic wrapper to make a call. bool Call(const std::string& operation, diff --git a/src/demo/main.cc b/src/demo/main.cc index 18d9512..e01f179 100644 --- a/src/demo/main.cc +++ b/src/demo/main.cc @@ -4,9 +4,9 @@ int main() { demo::Calculator calculator; - float x = 1.0; - float y = 2.0; - float result = 0.0; + double x = 1.0; + double y = 2.0; + double result = 0.0; if (calculator.Add(x, y, &result)) { printf("add: %.1f\n", result);