Skip to content

Commit b0e0c0a

Browse files
montdidiermrtazz
authored andcommitted
no-signal capability
this adds a method to the connection object to be able to turn off libcurl signals for use in multi-threaded context. closes mrtazz#67
1 parent d3d2f18 commit b0e0c0a

4 files changed

Lines changed: 35 additions & 0 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ your threads. Do not share connection objects across threads as this would
164164
mean accessing curl handles from multiple threads at the same time which is
165165
not allowed.
166166

167+
The connection level method SetNoSignal can be set to skip all signal handling. This is important in multi-threaded applications as DNS resolution timeouts use signals. The signal handlers quite readily get executed on other threads. Note that with this option DNS resolution timeouts do not work. If you have crashes in your multi-threaded executable that appear to be in DNS resolution, this is probably why.
168+
167169
In order to provide an easy to use API, the simple usage via the static
168170
methods implicitly calls the curl global functions and is therefore also **not
169171
thread-safe**.

include/restclient-cpp/connection.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class Connection {
9595
RestClient::HeaderFields headers;
9696
int timeout;
9797
bool followRedirects;
98+
bool noSignal;
9899
struct {
99100
std::string username;
100101
std::string password;
@@ -119,6 +120,9 @@ class Connection {
119120
// set connection timeout to seconds
120121
void SetTimeout(int seconds);
121122

123+
// set to not use signals
124+
void SetNoSignal(bool no);
125+
122126
// set whether to follow redirects
123127
void FollowRedirects(bool follow);
124128

@@ -169,6 +173,7 @@ class Connection {
169173
RestClient::HeaderFields headerFields;
170174
int timeout;
171175
bool followRedirects;
176+
bool noSignal;
172177
struct {
173178
std::string username;
174179
std::string password;

source/connection.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ RestClient::Connection::Connection(const std::string& baseUrl)
3434
this->baseUrl = baseUrl;
3535
this->timeout = 0;
3636
this->followRedirects = false;
37+
this->noSignal = false;
3738
}
3839

3940
RestClient::Connection::~Connection() {
@@ -55,6 +56,8 @@ RestClient::Connection::GetInfo() {
5556
ret.baseUrl = this->baseUrl;
5657
ret.headers = this->GetHeaders();
5758
ret.timeout = this->timeout;
59+
ret.followRedirects = this->followRedirects;
60+
ret.noSignal = this->noSignal;
5861
ret.basicAuth.username = this->basicAuth.username;
5962
ret.basicAuth.password = this->basicAuth.password;
6063
ret.customUserAgent = this->customUserAgent;
@@ -165,6 +168,18 @@ RestClient::Connection::SetTimeout(int seconds) {
165168
this->timeout = seconds;
166169
}
167170

171+
/**
172+
* @brief switch off curl signals for connection (see CURLOPT_NONSIGNAL). By
173+
* default signals are used, except when timeout is given.
174+
*
175+
* @param no - set to true switches signals off
176+
*
177+
*/
178+
void
179+
RestClient::Connection::SetNoSignal(bool no) {
180+
this->noSignal = no;
181+
}
182+
168183
/**
169184
* @brief set username and password for basic auth
170185
*
@@ -261,6 +276,12 @@ RestClient::Connection::performCurlRequest(const std::string& uri) {
261276
if (this->followRedirects == true) {
262277
curl_easy_setopt(this->curlHandle, CURLOPT_FOLLOWLOCATION, 1L);
263278
}
279+
280+
if (this->noSignal) {
281+
// multi-threaded and prevent entering foreign signal handler (e.g. JNI)
282+
curl_easy_setopt(this->curlHandle, CURLOPT_NOSIGNAL, 1);
283+
}
284+
264285
// if provided, supply CA path
265286
if (!this->caInfoFilePath.empty()) {
266287
curl_easy_setopt(this->curlHandle, CURLOPT_CAINFO,

test/test_connection.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,10 @@ TEST_F(ConnectionTest, TestHeadHeaders)
207207
EXPECT_EQ("bar", headers_returned["Foo"]);
208208
EXPECT_EQ("lol", headers_returned["Bla"]);
209209
}
210+
211+
TEST_F(ConnectionTest, TestNoSignal)
212+
{
213+
conn->SetNoSignal(true);
214+
RestClient::Response res = conn->get("/get");
215+
EXPECT_EQ(200, res.code);
216+
}

0 commit comments

Comments
 (0)