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:
|
case kEndpointConnectError:
|
||||||
return "Cannot connect to remote endpoint.";
|
return "Cannot connect to remote endpoint.";
|
||||||
|
|
||||||
|
case kSocketTimeoutError:
|
||||||
|
return "Operation timeout.";
|
||||||
|
|
||||||
case kSocketReadError:
|
case kSocketReadError:
|
||||||
return "Socket read error.";
|
return "Socket read error.";
|
||||||
|
|
||||||
@@ -38,23 +41,24 @@ const char* GetErrorMessage(ErrorCode error_code) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Parameter::Parameter(const std::string& key, const std::string& value)
|
Parameter::Parameter(const std::string& key, const std::string& value)
|
||||||
: key_(key) {
|
: key_(key), value_(value) {
|
||||||
value_ = LexicalCast<std::string>(value, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameter::Parameter(const std::string& key, int value)
|
Parameter::Parameter(const std::string& key, int value)
|
||||||
: key_(key) {
|
: 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) {
|
: key_(key) {
|
||||||
value_ = LexicalCast<std::string>(value, "");
|
char buf[32];
|
||||||
|
sprintf(buf, "%f", value);
|
||||||
|
value_ = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameter::Parameter(const std::string& key, bool value)
|
Parameter::Parameter(const std::string& key, bool value)
|
||||||
: key_(key) {
|
: key_(key) {
|
||||||
value_ = LexicalCast<std::string>(value, "");
|
value_ = value ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace csoap
|
} // 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 {
|
enum ErrorCode {
|
||||||
kNoError = 0, // OK
|
kNoError = 0, // OK
|
||||||
|
|
||||||
kHostResolveError,
|
kHostResolveError,
|
||||||
kEndpointConnectError,
|
kEndpointConnectError,
|
||||||
|
|
||||||
|
kSocketTimeoutError,
|
||||||
|
|
||||||
kSocketReadError,
|
kSocketReadError,
|
||||||
kSocketWriteError,
|
kSocketWriteError,
|
||||||
|
|
||||||
@@ -66,7 +53,7 @@ class Parameter {
|
|||||||
public:
|
public:
|
||||||
Parameter(const std::string& key, const std::string& value);
|
Parameter(const std::string& key, const std::string& value);
|
||||||
Parameter(const std::string& key, int 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);
|
Parameter(const std::string& key, bool value);
|
||||||
|
|
||||||
const char* c_key() const {
|
const char* c_key() const {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ void HttpRequest::ToString(std::string& req_string) const {
|
|||||||
|
|
||||||
req_string += kFieldContentLengthName;
|
req_string += kFieldContentLengthName;
|
||||||
req_string += ": ";
|
req_string += ": ";
|
||||||
req_string += LexicalCast<std::string>(content_length_, "0");
|
req_string += boost::lexical_cast<std::string>(content_length_);
|
||||||
req_string += kCRLF;
|
req_string += kCRLF;
|
||||||
|
|
||||||
req_string += "SOAPAction: ";
|
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,
|
ErrorCode HttpClient::SendRequest(const HttpRequest& request,
|
||||||
@@ -254,6 +255,8 @@ ErrorCode HttpClient::SendRequest(const HttpRequest& request,
|
|||||||
return kEndpointConnectError;
|
return kEndpointConnectError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetTimeout(socket);
|
||||||
|
|
||||||
std::string request_str;
|
std::string request_str;
|
||||||
request.ToString(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);
|
size_t len = socket.read_some(boost::asio::buffer(bytes_), ec);
|
||||||
|
|
||||||
if (len == 0 || ec) {
|
if (len == 0 || ec) {
|
||||||
return kSocketReadError;
|
if (ec.value() == WSAETIMEDOUT) {
|
||||||
|
return kSocketTimeoutError;
|
||||||
|
} else {
|
||||||
|
return kSocketReadError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the response piece just read.
|
// Parse the response piece just read.
|
||||||
@@ -288,4 +295,27 @@ ErrorCode HttpClient::SendRequest(const HttpRequest& request,
|
|||||||
return kNoError;
|
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
|
} // namespace csoap
|
||||||
|
|||||||
@@ -145,13 +145,22 @@ class HttpClient {
|
|||||||
public:
|
public:
|
||||||
HttpClient();
|
HttpClient();
|
||||||
|
|
||||||
|
// Set socket send & recv timeout.
|
||||||
|
void set_timeout_seconds(int seconds) {
|
||||||
|
timeout_seconds_ = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorCode SendRequest(const HttpRequest& request,
|
ErrorCode SendRequest(const HttpRequest& request,
|
||||||
const std::string& body,
|
const std::string& body,
|
||||||
HttpResponse* response);
|
HttpResponse* response);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetTimeout(boost::asio::ip::tcp::socket& socket);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::asio::io_service io_service_;
|
boost::asio::io_service io_service_;
|
||||||
std::array<char, 1024> bytes_;
|
std::array<char, 1024> bytes_;
|
||||||
|
int timeout_seconds_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace csoap
|
} // namespace csoap
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ Calculator::Calculator() {
|
|||||||
Init();
|
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);
|
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);
|
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);
|
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);
|
return Calc("divide", "numerator", "denominator", x, y, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,9 +38,9 @@ void Calculator::Init() {
|
|||||||
bool Calculator::Calc(const std::string& operation,
|
bool Calculator::Calc(const std::string& operation,
|
||||||
const std::string& x_name,
|
const std::string& x_name,
|
||||||
const std::string& y_name,
|
const std::string& y_name,
|
||||||
float x,
|
double x,
|
||||||
float y,
|
double y,
|
||||||
float* result) {
|
double* result) {
|
||||||
csoap::Parameter parameters[] = {
|
csoap::Parameter parameters[] = {
|
||||||
{ x_name, x },
|
{ x_name, x },
|
||||||
{ y_name, y }
|
{ y_name, y }
|
||||||
@@ -52,7 +52,7 @@ bool Calculator::Calc(const std::string& operation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
*result = boost::lexical_cast<float>(result_str);
|
*result = boost::lexical_cast<double>(result_str);
|
||||||
} catch (boost::bad_lexical_cast&) {
|
} catch (boost::bad_lexical_cast&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ class Calculator {
|
|||||||
public:
|
public:
|
||||||
Calculator();
|
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:
|
protected:
|
||||||
void Init();
|
void Init();
|
||||||
@@ -28,9 +28,9 @@ protected:
|
|||||||
bool Calc(const std::string& operation,
|
bool Calc(const std::string& operation,
|
||||||
const std::string& x_name,
|
const std::string& x_name,
|
||||||
const std::string& y_name,
|
const std::string& y_name,
|
||||||
float x,
|
double x,
|
||||||
float y,
|
double y,
|
||||||
float* result);
|
double* result);
|
||||||
|
|
||||||
// A generic wrapper to make a call.
|
// A generic wrapper to make a call.
|
||||||
bool Call(const std::string& operation,
|
bool Call(const std::string& operation,
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
int main() {
|
int main() {
|
||||||
demo::Calculator calculator;
|
demo::Calculator calculator;
|
||||||
|
|
||||||
float x = 1.0;
|
double x = 1.0;
|
||||||
float y = 2.0;
|
double y = 2.0;
|
||||||
float result = 0.0;
|
double result = 0.0;
|
||||||
|
|
||||||
if (calculator.Add(x, y, &result)) {
|
if (calculator.Add(x, y, &result)) {
|
||||||
printf("add: %.1f\n", result);
|
printf("add: %.1f\n", result);
|
||||||
|
|||||||
Reference in New Issue
Block a user