Refine type convertion; add timeout handling.

master
Adam Gu 8 years ago
parent eac855ae32
commit cff90c15fb

@ -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

@ -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,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<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,

@ -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);

Loading…
Cancel
Save