Refine type convertion; add timeout handling.
This commit is contained in:
+10
-6
@@ -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<std::string>(value, "");
|
||||
: key_(key), value_(value) {
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string& key, int value)
|
||||
: key_(key) {
|
||||
value_ = LexicalCast<std::string>(value, "");
|
||||
value_ = boost::lexical_cast<std::string>(value);
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string& key, float value)
|
||||
Parameter::Parameter(const std::string& key, double value)
|
||||
: key_(key) {
|
||||
value_ = LexicalCast<std::string>(value, "");
|
||||
char buf[32];
|
||||
sprintf(buf, "%f", value);
|
||||
value_ = buf;
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string& key, bool value)
|
||||
: key_(key) {
|
||||
value_ = LexicalCast<std::string>(value, "");
|
||||
value_ = value ? "true" : "false";
|
||||
}
|
||||
|
||||
} // namespace csoap
|
||||
|
||||
+3
-16
@@ -10,27 +10,14 @@ namespace csoap {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Wrapper for boost::lexcical_cast.
|
||||
// Usage:
|
||||
// LexicalCast<int>("123", 0);
|
||||
// LexicalCast<std::string>(123, "");
|
||||
template <typename To, typename From>
|
||||
To LexicalCast(const From& input, const To& default_output) {
|
||||
try {
|
||||
return boost::lexical_cast<To>(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 {
|
||||
|
||||
@@ -61,7 +61,7 @@ void HttpRequest::ToString(std::string& req_string) const {
|
||||
|
||||
req_string += kFieldContentLengthName;
|
||||
req_string += ": ";
|
||||
req_string += LexicalCast<std::string>(content_length_, "0");
|
||||
req_string += boost::lexical_cast<std::string>(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,8 +275,12 @@ ErrorCode HttpClient::SendRequest(const HttpRequest& request,
|
||||
size_t len = socket.read_some(boost::asio::buffer(bytes_), ec);
|
||||
|
||||
if (len == 0 || ec) {
|
||||
if (ec.value() == WSAETIMEDOUT) {
|
||||
return kSocketTimeoutError;
|
||||
} else {
|
||||
return kSocketReadError;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the response piece just read.
|
||||
// If the content has been fully received, next time flag "finished_" will
|
||||
@@ -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<const char*>(&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
|
||||
|
||||
@@ -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<char, 1024> bytes_;
|
||||
int timeout_seconds_;
|
||||
};
|
||||
|
||||
} // namespace csoap
|
||||
|
||||
@@ -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<float>(result_str);
|
||||
*result = boost::lexical_cast<double>(result_str);
|
||||
} catch (boost::bad_lexical_cast&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
+3
-3
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user