aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage/llcurl.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:50 -0500
committerJacek Antonelli2008-08-15 23:44:50 -0500
commit89fe5dab825a62a0e3fd8d248cbc91c65eb2a426 (patch)
treebcff14b7888d04a2fec799c59369f6095224bd08 /linden/indra/llmessage/llcurl.cpp
parentSecond Life viewer sources 1.13.3.2 (diff)
downloadmeta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.zip
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.gz
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.bz2
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.xz
Second Life viewer sources 1.14.0.0
Diffstat (limited to '')
-rw-r--r--linden/indra/llmessage/llcurl.cpp343
1 files changed, 343 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llcurl.cpp b/linden/indra/llmessage/llcurl.cpp
new file mode 100644
index 0000000..886697e
--- /dev/null
+++ b/linden/indra/llmessage/llcurl.cpp
@@ -0,0 +1,343 @@
1/*
2 * llcurl.cpp
3 * MacTester
4 *
5 * Created by Zero Linden on 10/15/06.
6 * Copyright 2006 __MyCompanyName__. All rights reserved.
7 *
8 */
9
10#include "llcurl.h"
11
12#include <iomanip>
13
14#include "llsdserialize.h"
15
16//////////////////////////////////////////////////////////////////////////////
17/*
18 The trick to getting curl to do keep-alives is to reuse the
19 same easy handle for the requests. It appears that curl
20 keeps a pool of connections alive for each easy handle, but
21 doesn't share them between easy handles. Therefore it is
22 important to keep a pool of easy handles and reuse them,
23 rather than create and destroy them with each request. This
24 code does this.
25
26 Furthermore, it would behoove us to keep track of which
27 hosts an easy handle was used for and pick an easy handle
28 that matches the next request. This code does not current
29 do this.
30 */
31
32using namespace std;
33
34LLCurl::Responder::Responder()
35 : mReferenceCount(0)
36{
37}
38LLCurl::Responder::~Responder()
39{
40}
41
42// virtual
43void LLCurl::Responder::error(U32 status, const std::stringstream& content)
44{
45 llinfos << "LLCurl::Responder::error " << status << ": " << content.str() << llendl;
46}
47
48// virtual
49void LLCurl::Responder::result(const std::stringstream& content)
50{
51}
52
53// virtual
54void LLCurl::Responder::completed(U32 status, const std::stringstream& content)
55{
56 if (200 <= status && status < 300)
57 {
58 result(content);
59 }
60 else
61 {
62 error(status, content);
63 }
64}
65
66
67namespace boost
68{
69 void intrusive_ptr_add_ref(LLCurl::Responder* p)
70 {
71 ++p->mReferenceCount;
72 }
73
74 void intrusive_ptr_release(LLCurl::Responder* p)
75 {
76 if(0 == --p->mReferenceCount)
77 {
78 delete p;
79 }
80 }
81};
82
83//////////////////////////////////////////////////////////////////////////////
84
85size_t
86curlOutputCallback(void* data, size_t size, size_t nmemb, void* user_data)
87{
88 stringstream& output = *(stringstream*)user_data;
89
90 size_t n = size * nmemb;
91 output.write((const char*)data, n);
92 if (!((istream&)output).good()) {
93 std::cerr << "WHAT!?!?!? istream side bad" << std::endl;
94 }
95 if (!((ostream&)output).good()) {
96 std::cerr << "WHAT!?!?!? ostream side bad" << std::endl;
97 }
98
99 return n;
100}
101
102// Only used if request contained a body (post or put), Not currently implemented.
103// size_t
104// curlRequestCallback(void* data, size_t size, size_t nmemb, void* user_data)
105// {
106// stringstream& request = *(stringstream*)user_data;
107
108// size_t n = size * nmemb;
109// request.read((char*)data, n);
110// return request.gcount();
111// }
112
113
114
115
116
117LLCurl::Easy::Easy()
118{
119 mHeaders = 0;
120 mHeaders = curl_slist_append(mHeaders, "Connection: keep-alive");
121 mHeaders = curl_slist_append(mHeaders, "Keep-alive: 300");
122 mHeaders = curl_slist_append(mHeaders, "Content-Type: application/xml");
123 // FIXME: shouldn't be there for GET/DELETE
124 // FIXME: should have ACCEPT headers
125
126 mHandle = curl_easy_init();
127}
128
129LLCurl::Easy::~Easy()
130{
131 curl_easy_cleanup(mHandle);
132 curl_slist_free_all(mHeaders);
133}
134
135void
136LLCurl::Easy::get(const string& url, ResponderPtr responder)
137{
138 prep(url, responder);
139 curl_easy_setopt(mHandle, CURLOPT_HTTPGET, 1);
140}
141
142void
143LLCurl::Easy::getByteRange(const string& url, S32 offset, S32 length, ResponderPtr responder)
144{
145 mRange = llformat("Range: bytes=%d-%d", offset,offset+length-1);
146 mHeaders = curl_slist_append(mHeaders, mRange.c_str());
147 prep(url, responder);
148 curl_easy_setopt(mHandle, CURLOPT_HTTPGET, 1);
149}
150
151void
152LLCurl::Easy::perform()
153{
154 report(curl_easy_perform(mHandle));
155}
156
157void
158LLCurl::Easy::prep(const std::string& url, ResponderPtr responder)
159{
160#if !LL_DARWIN
161 curl_easy_reset(mHandle); // SJB: doesn't exisit on OSX 10.3.9
162#else
163 // SJB: equivalent? fast?
164 curl_easy_cleanup(mHandle);
165 mHandle = curl_easy_init();
166#endif
167
168 curl_easy_setopt(mHandle, CURLOPT_PRIVATE, this);
169
170// curl_easy_setopt(mHandle, CURLOPT_VERBOSE, 1); // usefull for debugging
171 curl_easy_setopt(mHandle, CURLOPT_NOSIGNAL, 1);
172 curl_easy_setopt(mHandle, CURLOPT_WRITEFUNCTION, &curlOutputCallback);
173 curl_easy_setopt(mHandle, CURLOPT_WRITEDATA, &mOutput);
174#if 1 // For debug
175 curl_easy_setopt(mHandle, CURLOPT_HEADERFUNCTION, &curlOutputCallback);
176 curl_easy_setopt(mHandle, CURLOPT_HEADERDATA, &mHeaderOutput);
177#endif
178 curl_easy_setopt(mHandle, CURLOPT_ERRORBUFFER, &mErrorBuffer);
179 curl_easy_setopt(mHandle, CURLOPT_ENCODING, "");
180 curl_easy_setopt(mHandle, CURLOPT_SSL_VERIFYPEER, false);
181 curl_easy_setopt(mHandle, CURLOPT_HTTPHEADER, mHeaders);
182
183 mOutput.str("");
184 if (!((istream&)mOutput).good()) {
185 std::cerr << "WHAT!?!?!? istream side bad" << std::endl;
186 }
187 if (!((ostream&)mOutput).good()) {
188 std::cerr << "WHAT!?!?!? ostream side bad" << std::endl;
189 }
190
191 mURL = url;
192 curl_easy_setopt(mHandle, CURLOPT_URL, mURL.c_str());
193
194 mResponder = responder;
195}
196
197void
198LLCurl::Easy::report(CURLcode code)
199{
200 if (!mResponder) return;
201
202 long responseCode;
203
204 if (code == CURLE_OK)
205 {
206 curl_easy_getinfo(mHandle, CURLINFO_RESPONSE_CODE, &responseCode);
207 }
208 else
209 {
210 responseCode = 499;
211 }
212
213 mResponder->completed(responseCode, mOutput);
214 mResponder = NULL;
215}
216
217
218
219
220
221
222LLCurl::Multi::Multi()
223{
224 mHandle = curl_multi_init();
225}
226
227LLCurl::Multi::~Multi()
228{
229 // FIXME: should clean up excess handles in mFreeEasy
230 curl_multi_cleanup(mHandle);
231}
232
233
234void
235LLCurl::Multi::get(const std::string& url, ResponderPtr responder)
236{
237 LLCurl::Easy* easy = easyAlloc();
238 easy->get(url, responder);
239 curl_multi_add_handle(mHandle, easy->mHandle);
240}
241
242void
243LLCurl::Multi::getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr responder)
244{
245 LLCurl::Easy* easy = easyAlloc();
246 easy->getByteRange(url, offset, length, responder);
247 curl_multi_add_handle(mHandle, easy->mHandle);
248}
249
250void
251LLCurl::Multi::process()
252{
253 int count;
254 for (int call_count = 0; call_count < 5; call_count += 1)
255 {
256 if (CURLM_CALL_MULTI_PERFORM != curl_multi_perform(mHandle, &count))
257 {
258 break;
259 }
260 }
261
262 CURLMsg* msg;
263 int msgs_in_queue;
264 while ((msg = curl_multi_info_read(mHandle, &msgs_in_queue)))
265 {
266 if (msg->msg != CURLMSG_DONE) continue;
267 Easy* easy = 0;
268 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &easy);
269 if (!easy) continue;
270 easy->report(msg->data.result);
271
272 curl_multi_remove_handle(mHandle, easy->mHandle);
273 easyFree(easy);
274 }
275}
276
277
278
279LLCurl::Easy*
280LLCurl::Multi::easyAlloc()
281{
282 Easy* easy = 0;
283
284 if (mFreeEasy.empty())
285 {
286 easy = new Easy();
287 }
288 else
289 {
290 easy = mFreeEasy.back();
291 mFreeEasy.pop_back();
292 }
293
294 return easy;
295}
296
297void
298LLCurl::Multi::easyFree(Easy* easy)
299{
300 if (mFreeEasy.size() < 5)
301 {
302 mFreeEasy.push_back(easy);
303 }
304 else
305 {
306 delete easy;
307 }
308}
309
310
311
312namespace
313{
314 static LLCurl::Multi* sMainMulti = 0;
315
316 LLCurl::Multi*
317 mainMulti()
318 {
319 if (!sMainMulti) {
320 sMainMulti = new LLCurl::Multi();
321 }
322 return sMainMulti;
323 }
324}
325
326void
327LLCurl::get(const std::string& url, ResponderPtr responder)
328{
329 mainMulti()->get(url, responder);
330}
331
332void
333LLCurl::getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr responder)
334{
335 mainMulti()->getByteRange(url, offset, length, responder);
336}
337
338void
339LLCurl::process()
340{
341 mainMulti()->process();
342}
343