1 /**
2 * @file http.cpp
3 * @brief Generic host HTTP I/O interface
4 *
5 * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
6 *
7 * This file is part of the MEGA SDK - Client Access Engine.
8 *
9 * Applications using the MEGA API must present a valid application key
10 * and comply with the the rules set forth in the Terms of Service.
11 *
12 * The MEGA SDK is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * @copyright Simplified (2-clause) BSD License.
17 *
18 * You should have received a copy of the license along with this
19 * program.
20 */
21
22 #include "mega/http.h"
23 #include "mega/megaclient.h"
24 #include "mega/logging.h"
25 #include "mega/proxy.h"
26 #include "mega/base64.h"
27 #include "mega/testhooks.h"
28
29 #if defined(WIN32) && !defined(WINDOWS_PHONE)
30 #include <winhttp.h>
31 #endif
32
33 #if defined(__APPLE__) && !(TARGET_OS_IPHONE)
34 #include "mega/osx/osxutils.h"
35 #endif
36
37 namespace mega {
38
39 // interval to calculate the mean speed (ds)
40 const int SpeedController::SPEED_MEAN_INTERVAL_DS = 50;
41
42 // max time to calculate the mean speed
43 const int SpeedController::SPEED_MAX_VALUES = 10000;
44
45 // data receive timeout (ds)
46 const int HttpIO::NETWORKTIMEOUT = 6000;
47
48 // request timeout (ds)
49 const int HttpIO::REQUESTTIMEOUT = 1200;
50
51 // wait request timeout (ds)
52 const int HttpIO::SCREQUESTTIMEOUT = 400;
53
54 // connect timeout (ds)
55 const int HttpIO::CONNECTTIMEOUT = 120;
56
57 #ifdef _WIN32
mega_inet_ntop(int af,const void * src,char * dst,int cnt)58 const char* mega_inet_ntop(int af, const void* src, char* dst, int cnt)
59 {
60 wchar_t ip[INET6_ADDRSTRLEN];
61 int len = INET6_ADDRSTRLEN;
62 int ret = 1;
63
64 if (af == AF_INET)
65 {
66 struct sockaddr_in in = {};
67 in.sin_family = AF_INET;
68 memcpy(&in.sin_addr, src, sizeof(struct in_addr));
69 ret = WSAAddressToString((struct sockaddr*) &in, sizeof(struct sockaddr_in), 0, ip, (LPDWORD)&len);
70 }
71 else if (af == AF_INET6)
72 {
73 struct sockaddr_in6 in = {};
74 in.sin6_family = AF_INET6;
75 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
76 ret = WSAAddressToString((struct sockaddr*) &in, sizeof(struct sockaddr_in6), 0, ip, (LPDWORD)&len);
77 }
78
79 if (ret != 0)
80 {
81 return NULL;
82 }
83
84 if (!WideCharToMultiByte(CP_UTF8, 0, ip, len, dst, cnt, NULL, NULL))
85 {
86 return NULL;
87 }
88
89 return dst;
90 }
91 #endif
92
HttpIO()93 HttpIO::HttpIO()
94 {
95 success = false;
96 noinetds = 0;
97 inetback = false;
98 lastdata = NEVER;
99 downloadSpeed = 0;
100 uploadSpeed = 0;
101 }
102
103 // signal Internet status - if the Internet was down for more than one minute,
104 // set the inetback flag to trigger a reconnect
inetstatus(bool up)105 void HttpIO::inetstatus(bool up)
106 {
107 if (up)
108 {
109 if (noinetds && Waiter::ds - noinetds > 600)
110 {
111 inetback = true;
112 }
113
114 noinetds = 0;
115 }
116 else if (!noinetds)
117 {
118 noinetds = Waiter::ds;
119 }
120 }
121
122 // returns true once if an outage just ended
inetisback()123 bool HttpIO::inetisback()
124 {
125 if(inetback)
126 {
127 inetback = false;
128 return true;
129 }
130
131 return false;
132 }
133
updatedownloadspeed(m_off_t size)134 void HttpIO::updatedownloadspeed(m_off_t size)
135 {
136 downloadSpeed = downloadSpeedController.calculateSpeed(size);
137 }
138
updateuploadspeed(m_off_t size)139 void HttpIO::updateuploadspeed(m_off_t size)
140 {
141 uploadSpeed = uploadSpeedController.calculateSpeed(size);
142 }
143
getautoproxy()144 Proxy *HttpIO::getautoproxy()
145 {
146 Proxy* proxy = new Proxy();
147 proxy->setProxyType(Proxy::NONE);
148
149 #if defined(WIN32) && !defined(WINDOWS_PHONE)
150 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig = { 0 };
151
152 if (WinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig) == TRUE)
153 {
154 if (ieProxyConfig.lpszProxy)
155 {
156 string proxyURL;
157 proxy->setProxyType(Proxy::CUSTOM);
158 int len = static_cast<int>(wcslen(ieProxyConfig.lpszProxy));
159 proxyURL.assign((const char*)ieProxyConfig.lpszProxy, len * sizeof(wchar_t) + 1);
160
161 // only save one proxy
162 for (int i = 0; i < len; i++)
163 {
164 wchar_t* character = (wchar_t*)(proxyURL.data() + i * sizeof(wchar_t));
165
166 if (*character == ' ' || *character == ';')
167 {
168 proxyURL.resize(i*sizeof(wchar_t));
169 len = i;
170 break;
171 }
172 }
173
174 // remove protocol prefix, if any
175 for (int i = len - 1; i >= 0; i--)
176 {
177 wchar_t* character = (wchar_t*)(proxyURL.data() + i * sizeof(wchar_t));
178
179 if (*character == '/' || *character == '=')
180 {
181 proxyURL = proxyURL.substr((i + 1) * sizeof(wchar_t));
182 break;
183 }
184 }
185
186 proxy->setProxyURL(&proxyURL);
187 }
188 else if (ieProxyConfig.lpszAutoConfigUrl || ieProxyConfig.fAutoDetect == TRUE)
189 {
190 WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
191
192 if (ieProxyConfig.lpszAutoConfigUrl)
193 {
194 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
195 autoProxyOptions.lpszAutoConfigUrl = ieProxyConfig.lpszAutoConfigUrl;
196 autoProxyOptions.dwAutoDetectFlags = 0;
197 }
198 else
199 {
200 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
201 autoProxyOptions.lpszAutoConfigUrl = NULL;
202 autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
203 }
204
205 autoProxyOptions.fAutoLogonIfChallenged = TRUE;
206 autoProxyOptions.lpvReserved = NULL;
207 autoProxyOptions.dwReserved = 0;
208
209 WINHTTP_PROXY_INFO proxyInfo;
210
211 HINTERNET hSession = WinHttpOpen(L"MEGAsync proxy detection",
212 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
213 WINHTTP_NO_PROXY_NAME,
214 WINHTTP_NO_PROXY_BYPASS,
215 WINHTTP_FLAG_ASYNC);
216
217 if (WinHttpGetProxyForUrl(hSession, L"https://g.api.mega.co.nz/", &autoProxyOptions, &proxyInfo))
218 {
219 if (proxyInfo.lpszProxy)
220 {
221 string proxyURL;
222 proxy->setProxyType(Proxy::CUSTOM);
223 proxyURL.assign((const char*)proxyInfo.lpszProxy, wcslen(proxyInfo.lpszProxy) * sizeof(wchar_t));
224 proxy->setProxyURL(&proxyURL);
225 }
226 }
227 WinHttpCloseHandle(hSession);
228 }
229 }
230
231 if (ieProxyConfig.lpszProxy)
232 {
233 GlobalFree(ieProxyConfig.lpszProxy);
234 }
235
236 if (ieProxyConfig.lpszProxyBypass)
237 {
238 GlobalFree(ieProxyConfig.lpszProxyBypass);
239 }
240
241 if (ieProxyConfig.lpszAutoConfigUrl)
242 {
243 GlobalFree(ieProxyConfig.lpszAutoConfigUrl);
244 }
245 #endif
246
247 #if defined(__APPLE__) && !(TARGET_OS_IPHONE)
248 getOSXproxy(proxy);
249 #endif
250
251 return proxy;
252 }
253
getMEGADNSservers(string * dnsservers,bool getfromnetwork)254 void HttpIO::getMEGADNSservers(string *dnsservers, bool getfromnetwork)
255 {
256 if (!dnsservers)
257 {
258 return;
259 }
260
261 dnsservers->clear();
262 if (getfromnetwork)
263 {
264 struct addrinfo *aiList = NULL;
265 struct addrinfo *hp;
266
267 struct addrinfo hints = {};
268 hints.ai_family = AF_UNSPEC;
269
270 #ifndef __MINGW32__
271 hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
272 #endif
273
274 if (!getaddrinfo("ns.mega.co.nz", NULL, &hints, &aiList))
275 {
276 hp = aiList;
277 while (hp)
278 {
279 char straddr[INET6_ADDRSTRLEN];
280 straddr[0] = 0;
281
282 if (hp->ai_family == AF_INET)
283 {
284 sockaddr_in *addr = (sockaddr_in *)hp->ai_addr;
285 mega_inet_ntop(hp->ai_family, &addr->sin_addr, straddr, sizeof(straddr));
286 }
287 else if(hp->ai_family == AF_INET6)
288 {
289 sockaddr_in6 *addr = (sockaddr_in6 *)hp->ai_addr;
290 mega_inet_ntop(hp->ai_family, &addr->sin6_addr, straddr, sizeof(straddr));
291 }
292
293 if (straddr[0])
294 {
295 if(dnsservers->size())
296 {
297 dnsservers->append(",");
298 }
299 dnsservers->append(straddr);
300 }
301
302 hp = hp->ai_next;
303 }
304 freeaddrinfo(aiList);
305 }
306 }
307
308 if (!getfromnetwork || !dnsservers->size())
309 {
310 *dnsservers = MEGA_DNS_SERVERS;
311 LOG_info << "Using hardcoded MEGA DNS servers: " << *dnsservers;
312 }
313 else
314 {
315 LOG_info << "Using current MEGA DNS servers: " << *dnsservers;
316 }
317 }
318
setmaxdownloadspeed(m_off_t)319 bool HttpIO::setmaxdownloadspeed(m_off_t)
320 {
321 return false;
322 }
323
setmaxuploadspeed(m_off_t)324 bool HttpIO::setmaxuploadspeed(m_off_t)
325 {
326 return false;
327 }
328
getmaxdownloadspeed()329 m_off_t HttpIO::getmaxdownloadspeed()
330 {
331 return 0;
332 }
333
getmaxuploadspeed()334 m_off_t HttpIO::getmaxuploadspeed()
335 {
336 return 0;
337 }
338
post(MegaClient * client,const char * data,unsigned len)339 void HttpReq::post(MegaClient* client, const char* data, unsigned len)
340 {
341 if (httpio)
342 {
343 LOG_warn << "Ensuring that the request is finished before sending it again";
344 httpio->cancel(this);
345 init();
346 }
347
348 httpio = client->httpio;
349 bufpos = 0;
350 outpos = 0;
351 notifiedbufpos = 0;
352 inpurge = 0;
353 method = METHOD_POST;
354 contentlength = -1;
355 lastdata = Waiter::ds;
356
357 DEBUG_TEST_HOOK_HTTPREQ_POST(this)
358
359 httpio->post(this, data, len);
360 }
361
get(MegaClient * client)362 void HttpReq::get(MegaClient *client)
363 {
364 if (httpio)
365 {
366 LOG_warn << "Ensuring that the request is finished before sending it again";
367 httpio->cancel(this);
368 init();
369 }
370
371 httpio = client->httpio;
372 bufpos = 0;
373 outpos = 0;
374 notifiedbufpos = 0;
375 inpurge = 0;
376 method = METHOD_GET;
377 contentlength = -1;
378 lastdata = Waiter::ds;
379
380 httpio->post(this);
381 }
382
dns(MegaClient * client)383 void HttpReq::dns(MegaClient *client)
384 {
385 if (httpio)
386 {
387 LOG_warn << "Ensuring that the request is finished before sending it again";
388 httpio->cancel(this);
389 init();
390 }
391
392 httpio = client->httpio;
393 bufpos = 0;
394 outpos = 0;
395 notifiedbufpos = 0;
396 inpurge = 0;
397 method = METHOD_NONE;
398 contentlength = -1;
399 lastdata = Waiter::ds;
400
401 httpio->post(this);
402 }
403
disconnect()404 void HttpReq::disconnect()
405 {
406 if (httpio)
407 {
408 httpio->cancel(this);
409 httpio = NULL;
410 init();
411 }
412 }
413
HttpReq(bool b)414 HttpReq::HttpReq(bool b)
415 {
416 binary = b;
417 status = REQ_READY;
418 buf = NULL;
419 httpio = NULL;
420 httpiohandle = NULL;
421 out = &outbuf;
422 method = METHOD_NONE;
423 timeoutms = 0;
424 type = REQ_JSON;
425 buflen = 0;
426 protect = false;
427 minspeed = false;
428
429 init();
430 }
431
~HttpReq()432 HttpReq::~HttpReq()
433 {
434 if (httpio)
435 {
436 httpio->cancel(this);
437 }
438
439 delete[] buf;
440 }
441
init()442 void HttpReq::init()
443 {
444 httpstatus = 0;
445 inpurge = 0;
446 sslcheckfailed = false;
447 bufpos = 0;
448 notifiedbufpos = 0;
449 contentlength = 0;
450 timeleft = -1;
451 lastdata = NEVER;
452 outpos = 0;
453 in.clear();
454 contenttype.clear();
455 }
456
setreq(const char * u,contenttype_t t)457 void HttpReq::setreq(const char* u, contenttype_t t)
458 {
459 if (u)
460 {
461 posturl = u;
462 }
463
464 type = t;
465 }
466
467 // add data to fixed or variable buffer
put(void * data,unsigned len,bool purge)468 void HttpReq::put(void* data, unsigned len, bool purge)
469 {
470 if (buf)
471 {
472 if (bufpos + len > buflen)
473 {
474 len = static_cast<unsigned>(buflen - bufpos);
475 }
476
477 memcpy(buf + bufpos, data, len);
478 }
479 else
480 {
481 if (inpurge && purge)
482 {
483 in.erase(0, inpurge);
484 inpurge = 0;
485 }
486
487 in.append((char*)data, len);
488 }
489
490 bufpos += len;
491 }
492
493
http_buf_t(byte * b,size_t s,size_t e)494 HttpReq::http_buf_t::http_buf_t(byte* b, size_t s, size_t e)
495 : start(s), end(e), buf(b)
496 {
497 }
498
~http_buf_t()499 HttpReq::http_buf_t::~http_buf_t()
500 {
501 delete[] buf;
502 }
503
swap(http_buf_t & other)504 void HttpReq::http_buf_t::swap(http_buf_t& other)
505 {
506 byte* tb = buf; buf = other.buf; other.buf = tb;
507 size_t ts = start; start = other.start; other.start = ts;
508 size_t te = end; end = other.end; other.end = te;
509 }
510
isNull()511 bool HttpReq::http_buf_t::isNull()
512 {
513 return buf == NULL;
514 }
515
datastart()516 byte* HttpReq::http_buf_t::datastart()
517 {
518 return buf + start;
519 }
520
datalen()521 size_t HttpReq::http_buf_t::datalen()
522 {
523 return end - start;
524 }
525
526
527 // give up ownership of the buffer for client to use.
release_buf()528 struct HttpReq::http_buf_t* HttpReq::release_buf()
529 {
530 HttpReq::http_buf_t* result = new HttpReq::http_buf_t(buf, inpurge, (size_t)bufpos);
531 buf = NULL;
532 inpurge = 0;
533 buflen = 0;
534 bufpos = 0;
535 outpos = 0;
536 notifiedbufpos = 0;
537 contentlength = -1;
538 in.clear();
539 return result;
540 }
541
542
data()543 char* HttpReq::data()
544 {
545 return (char*)in.data() + inpurge;
546 }
547
size()548 size_t HttpReq::size()
549 {
550 return in.size() - inpurge;
551 }
552
553 // set amount of purgeable in data at 0
purge(size_t numbytes)554 void HttpReq::purge(size_t numbytes)
555 {
556 inpurge += numbytes;
557 }
558
559 // set total response size
setcontentlength(m_off_t len)560 void HttpReq::setcontentlength(m_off_t len)
561 {
562 if (!buf && type != REQ_BINARY)
563 {
564 in.reserve(static_cast<size_t>(len));
565 }
566
567 contentlength = len;
568 }
569
570 // make space for receiving data; adjust len if out of space
reserveput(unsigned * len)571 byte* HttpReq::reserveput(unsigned* len)
572 {
573 if (buf)
574 {
575 if (bufpos + *len > buflen)
576 {
577 *len = static_cast<unsigned>(buflen - bufpos);
578 }
579
580 return buf + bufpos;
581 }
582 else
583 {
584 if (inpurge)
585 {
586 // FIXME: optimize erase()/resize() -> single copy/resize()
587 in.erase(0, inpurge);
588 bufpos -= inpurge;
589 inpurge = 0;
590 }
591
592 if (bufpos + *len > (int) in.size())
593 {
594 in.resize(static_cast<size_t>(bufpos + *len));
595 }
596
597 *len = static_cast<unsigned>(in.size() - bufpos);
598
599 return (byte*)in.data() + bufpos;
600 }
601 }
602
603 // number of bytes transferred in this request
transferred(MegaClient *)604 m_off_t HttpReq::transferred(MegaClient*)
605 {
606 if (buf)
607 {
608 return bufpos;
609 }
610 else
611 {
612 return in.size();
613 }
614 }
615
HttpReqDL()616 HttpReqDL::HttpReqDL()
617 : dlpos(0)
618 , buffer_released(false)
619 {
620 }
621
622 // prepare file chunk download
prepare(const char * tempurl,SymmCipher *,uint64_t,m_off_t pos,m_off_t npos)623 void HttpReqDL::prepare(const char* tempurl, SymmCipher* /*key*/,
624 uint64_t /*ctriv*/, m_off_t pos,
625 m_off_t npos)
626 {
627 char urlbuf[512];
628
629 snprintf(urlbuf, sizeof urlbuf, "%s/%" PRIu64 "-%" PRIu64, tempurl, pos, npos ? npos - 1 : 0);
630 setreq(urlbuf, REQ_BINARY);
631
632 dlpos = pos;
633 size = (unsigned)(npos - pos);
634 buffer_released = false;
635
636 if (!buf || buflen != size)
637 {
638 // (re)allocate buffer
639 if (buf)
640 {
641 delete[] buf;
642 buf = NULL;
643 }
644
645 if (size)
646 {
647 buf = new byte[(size + SymmCipher::BLOCKSIZE - 1) & - SymmCipher::BLOCKSIZE];
648 }
649 buflen = size;
650 }
651 }
652
653
654
EncryptByChunks(SymmCipher * k,chunkmac_map * m,uint64_t iv)655 EncryptByChunks::EncryptByChunks(SymmCipher* k, chunkmac_map* m, uint64_t iv) : key(k), macs(m), ctriv(iv)
656 {
657 memset(crc, 0, CRCSIZE);
658 }
659
updateCRC(byte * data,unsigned size,unsigned offset)660 void EncryptByChunks::updateCRC(byte* data, unsigned size, unsigned offset)
661 {
662 uint32_t *intc = (uint32_t *)crc;
663
664 unsigned ol = offset % CRCSIZE;
665 if (ol)
666 {
667 unsigned ll = CRCSIZE - ol;
668 if (ll > size) //last chunks could be smaller than CRCSIZE!
669 {
670 ll = size;
671 }
672 size -= ll;
673 while (ll--)
674 {
675 crc[ol++] ^= *data++;
676 }
677 }
678
679 uint32_t *intdata = (uint32_t *)data;
680 int ll = size % CRCSIZE;
681 int l = size / CRCSIZE;
682 if (l)
683 {
684 l *= 3;
685 while (l)
686 {
687 l -= 3;
688 intc[0] ^= intdata[l];
689 intc[1] ^= intdata[l + 1];
690 intc[2] ^= intdata[l + 2];
691 }
692 }
693 if (ll)
694 {
695 data += (size - ll);
696 while (ll--)
697 {
698 crc[ll] ^= data[ll];
699 }
700 }
701 }
702
encrypt(m_off_t pos,m_off_t npos,string & urlSuffix)703 bool EncryptByChunks::encrypt(m_off_t pos, m_off_t npos, string& urlSuffix)
704 {
705 byte* buf;
706 m_off_t startpos = pos;
707 m_off_t finalpos = npos;
708 m_off_t endpos = ChunkedHash::chunkceil(startpos, finalpos);
709 m_off_t chunksize = endpos - startpos;
710 while (chunksize)
711 {
712 byte mac[SymmCipher::BLOCKSIZE] = { 0 };
713 buf = nextbuffer(unsigned(chunksize));
714 if (!buf) return false;
715 key->ctr_crypt(buf, unsigned(chunksize), startpos, ctriv, mac, 1);
716 memcpy((*macs)[startpos].mac, mac, sizeof mac);
717 (*macs)[startpos].finished = false; // finished is only set true after confirmation of the chunk uploading.
718 LOG_debug << "Encrypted chunk: " << startpos << " - " << endpos << " Size: " << chunksize;
719
720 updateCRC(buf, unsigned(chunksize), unsigned(startpos - pos));
721
722 startpos = endpos;
723 endpos = ChunkedHash::chunkceil(startpos, finalpos);
724 chunksize = endpos - startpos;
725 }
726 assert(endpos == finalpos);
727 buf = nextbuffer(0); // last call in case caller does buffer post-processing (such as write to file as we go)
728
729 ostringstream s;
730 s << "/" << pos << "?c=" << Base64Str<EncryptByChunks::CRCSIZE>(crc);
731 urlSuffix = s.str();
732
733 return !!buf;
734 }
735
736
EncryptBufferByChunks(byte * b,SymmCipher * k,chunkmac_map * m,uint64_t iv)737 EncryptBufferByChunks::EncryptBufferByChunks(byte* b, SymmCipher* k, chunkmac_map* m, uint64_t iv)
738 : EncryptByChunks(k, m, iv)
739 , chunkstart(b)
740 {
741 }
742
nextbuffer(unsigned bufsize)743 byte* EncryptBufferByChunks::nextbuffer(unsigned bufsize)
744 {
745 byte* pos = chunkstart;
746 chunkstart += bufsize;
747 return pos;
748 }
749
750 // prepare chunk for uploading: mac and encrypt
prepare(const char * tempurl,SymmCipher * key,uint64_t ctriv,m_off_t pos,m_off_t npos)751 void HttpReqUL::prepare(const char* tempurl, SymmCipher* key,
752 uint64_t ctriv, m_off_t pos,
753 m_off_t npos)
754 {
755 EncryptBufferByChunks eb((byte*)out->data(), key, &mChunkmacs, ctriv);
756
757 string urlSuffix;
758 eb.encrypt(pos, npos, urlSuffix);
759
760 // unpad for POSTing
761 size = (unsigned)(npos - pos);
762 out->resize(size);
763
764 setreq((tempurl + urlSuffix).c_str(), REQ_BINARY);
765 }
766
767 // number of bytes sent in this request
transferred(MegaClient * client)768 m_off_t HttpReqUL::transferred(MegaClient* client)
769 {
770 if (httpiohandle)
771 {
772 return client->httpio->postpos(httpiohandle);
773 }
774
775 return 0;
776 }
777
SpeedController()778 SpeedController::SpeedController()
779 {
780 partialBytes = 0;
781 meanSpeed = 0;
782 lastUpdate = 0;
783 speedCounter = 0;
784 }
785
calculateSpeed(long long numBytes)786 m_off_t SpeedController::calculateSpeed(long long numBytes)
787 {
788 dstime currentTime = Waiter::ds;
789 if (numBytes <= 0 && lastUpdate == currentTime)
790 {
791 return (partialBytes * 10) / SPEED_MEAN_INTERVAL_DS;
792 }
793
794 while (transferBytes.size())
795 {
796 map<dstime, m_off_t>::iterator it = transferBytes.begin();
797 dstime deltaTime = currentTime - it->first;
798 if (deltaTime < SPEED_MEAN_INTERVAL_DS)
799 {
800 break;
801 }
802
803 partialBytes -= it->second;
804 transferBytes.erase(it);
805 }
806
807 if (numBytes > 0)
808 {
809 transferBytes[currentTime] += numBytes;
810 partialBytes += numBytes;
811 }
812
813 m_off_t speed = (partialBytes * 10) / SPEED_MEAN_INTERVAL_DS;
814 if (numBytes)
815 {
816 meanSpeed = meanSpeed * speedCounter + speed;
817 speedCounter++;
818 meanSpeed /= speedCounter;
819 if (speedCounter > SPEED_MAX_VALUES)
820 {
821 speedCounter = SPEED_MAX_VALUES;
822 }
823 }
824 lastUpdate = currentTime;
825 return speed;
826 }
827
getMeanSpeed()828 m_off_t SpeedController::getMeanSpeed()
829 {
830 return meanSpeed;
831 }
832
GenericHttpReq(PrnGen & rng,bool binary)833 GenericHttpReq::GenericHttpReq(PrnGen &rng, bool binary)
834 : HttpReq(binary), bt(rng), maxbt(rng)
835 {
836 tag = 0;
837 maxretries = 0;
838 numretry = 0;
839 isbtactive = false;
840 }
841
842 } // namespace
843