Changeset 13863
- Timestamp:
- Jan 24, 2013, 11:59:52 PM (8 years ago)
- Location:
- trunk/libtransmission
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/bandwidth.c
r13625 r13863 22 22 23 23 #define dbgmsg(...) \ 24 do { \ 25 if (tr_deepLoggingIsActive ()) \ 26 tr_deepLog (__FILE__, __LINE__, NULL, __VA_ARGS__); \ 27 } while (0) 24 do \ 25 { \ 26 if (tr_deepLoggingIsActive ()) \ 27 tr_deepLog (__FILE__, __LINE__, NULL, __VA_ARGS__); \ 28 } \ 29 while (0) 28 30 29 31 /*** … … 34 36 getSpeed_Bps (const struct bratecontrol * r, unsigned int interval_msec, uint64_t now) 35 37 { 36 37 38 39 40 { 41 42 43 44 45 46 38 if (!now) 39 now = tr_time_msec (); 40 41 if (now != r->cache_time) 42 { 43 int i = r->newest; 44 uint64_t bytes = 0; 45 const uint64_t cutoff = now - interval_msec; 46 struct bratecontrol * rvolatile = (struct bratecontrol*) r; 47 48 for (;;) 47 49 { 48 if (r->transfers[i].date <= cutoff) 49 break; 50 51 bytes += r->transfers[i].size; 52 53 if (--i == -1) i = HISTORY_SIZE - 1; /* circular history */ 54 if (i == r->newest) break; /* we've come all the way around */ 50 if (r->transfers[i].date <= cutoff) 51 break; 52 53 bytes += r->transfers[i].size; 54 55 if (--i == -1) 56 i = HISTORY_SIZE - 1; /* circular history */ 57 58 if (i == r->newest) 59 break; /* we've come all the way around */ 55 60 } 56 61 57 58 59 } 60 61 62 rvolatile->cache_val = (unsigned int)((bytes * 1000u) / interval_msec); 63 rvolatile->cache_time = now; 64 } 65 66 return r->cache_val; 62 67 } 63 68 … … 65 70 bytesUsed (const uint64_t now, struct bratecontrol * r, size_t size) 66 71 { 67 if (r->transfers[r->newest].date + GRANULARITY_MSEC >= now) 68 r->transfers[r->newest].size += size; 69 else 70 { 71 if (++r->newest == HISTORY_SIZE) r->newest = 0; 72 r->transfers[r->newest].date = now; 73 r->transfers[r->newest].size = size; 74 } 75 76 /* invalidate cache_val*/ 77 r->cache_time = 0; 72 if (r->transfers[r->newest].date + GRANULARITY_MSEC >= now) 73 { 74 r->transfers[r->newest].size += size; 75 } 76 else 77 { 78 if (++r->newest == HISTORY_SIZE) 79 r->newest = 0; 80 r->transfers[r->newest].date = now; 81 r->transfers[r->newest].size = size; 82 } 83 84 /* invalidate cache_val*/ 85 r->cache_time = 0; 78 86 } 79 87 … … 86 94 compareBandwidth (const void * va, const void * vb) 87 95 { 88 89 90 96 const tr_bandwidth * a = va; 97 const tr_bandwidth * b = vb; 98 return a->uniqueKey - b->uniqueKey; 91 99 } 92 100 … … 98 106 tr_bandwidthConstruct (tr_bandwidth * b, tr_session * session, tr_bandwidth * parent) 99 107 { 100 101 102 103 104 105 106 107 108 108 static unsigned int uniqueKey = 0; 109 110 b->session = session; 111 b->children = TR_PTR_ARRAY_INIT; 112 b->magicNumber = BANDWIDTH_MAGIC_NUMBER; 113 b->uniqueKey = uniqueKey++; 114 b->band[TR_UP].honorParentLimits = true; 115 b->band[TR_DOWN].honorParentLimits = true; 116 tr_bandwidthSetParent (b, parent); 109 117 } 110 118 … … 112 120 tr_bandwidthDestruct (tr_bandwidth * b) 113 121 { 114 115 116 117 118 119 122 assert (tr_isBandwidth (b)); 123 124 tr_bandwidthSetParent (b, NULL); 125 tr_ptrArrayDestruct (&b->children, NULL); 126 127 memset (b, ~0, sizeof (tr_bandwidth)); 120 128 } 121 129 … … 128 136 tr_bandwidth * parent) 129 137 { 130 131 132 133 134 { 135 136 137 138 139 140 141 142 143 144 } 145 146 147 { 148 149 150 151 152 153 154 138 assert (tr_isBandwidth (b)); 139 assert (b != parent); 140 141 if (b->parent) 142 { 143 void * removed; 144 145 assert (tr_isBandwidth (b->parent)); 146 147 removed = tr_ptrArrayRemoveSorted (&b->parent->children, b, compareBandwidth); 148 assert (removed == b); 149 assert (tr_ptrArrayFindSorted (&b->parent->children, b, compareBandwidth) == NULL); 150 151 b->parent = NULL; 152 } 153 154 if (parent) 155 { 156 assert (tr_isBandwidth (parent)); 157 assert (parent->parent != b); 158 159 assert (tr_ptrArrayFindSorted (&parent->children, b, compareBandwidth) == NULL); 160 tr_ptrArrayInsertSorted (&parent->children, b, compareBandwidth); 161 assert (tr_ptrArrayFindSorted (&parent->children, b, compareBandwidth) == b); 162 b->parent = parent; 155 163 } 156 164 } … … 167 175 tr_ptrArray * peer_pool) 168 176 { 169 const tr_priority_t priority = MAX (parent_priority, b->priority); 170 171 assert (tr_isBandwidth (b)); 172 assert (tr_isDirection (dir)); 173 174 /* set the available bandwidth */ 175 if (b->band[dir].isLimited) 176 { 177 const uint64_t nextPulseSpeed = b->band[dir].desiredSpeed_Bps; 178 b->band[dir].bytesLeft = (unsigned int)(nextPulseSpeed * period_msec) / 1000u; 179 } 180 181 /* add this bandwidth's peer, if any, to the peer pool */ 182 if (b->peer != NULL) { 183 b->peer->priority = priority; 184 tr_ptrArrayAppend (peer_pool, b->peer); 185 } 186 187 /* traverse & repeat for the subtree */ 188 if (1) { 189 int i; 190 struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayBase (&b->children); 191 const int n = tr_ptrArraySize (&b->children); 192 for (i=0; i<n; ++i) 193 allocateBandwidth (children[i], priority, dir, period_msec, peer_pool); 177 const tr_priority_t priority = MAX (parent_priority, b->priority); 178 179 assert (tr_isBandwidth (b)); 180 assert (tr_isDirection (dir)); 181 182 /* set the available bandwidth */ 183 if (b->band[dir].isLimited) 184 { 185 const uint64_t nextPulseSpeed = b->band[dir].desiredSpeed_Bps; 186 b->band[dir].bytesLeft = (unsigned int)(nextPulseSpeed * period_msec) / 1000u; 187 } 188 189 /* add this bandwidth's peer, if any, to the peer pool */ 190 if (b->peer != NULL) 191 { 192 b->peer->priority = priority; 193 tr_ptrArrayAppend (peer_pool, b->peer); 194 } 195 196 /* traverse & repeat for the subtree */ 197 if (1) 198 { 199 int i; 200 struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayBase (&b->children); 201 const int n = tr_ptrArraySize (&b->children); 202 for (i=0; i<n; ++i) 203 allocateBandwidth (children[i], priority, dir, period_msec, peer_pool); 194 204 } 195 205 } … … 198 208 phaseOne (tr_ptrArray * peerArray, tr_direction dir) 199 209 { 200 int n; 201 int peerCount = tr_ptrArraySize (peerArray); 202 struct tr_peerIo ** peers = (struct tr_peerIo**) tr_ptrArrayBase (peerArray); 203 204 /* First phase of IO. Tries to distribute bandwidth fairly to keep faster 205 * peers from starving the others. Loop through the peers, giving each a 206 * small chunk of bandwidth. Keep looping until we run out of bandwidth 207 * and/or peers that can use it */ 208 n = peerCount; 209 dbgmsg ("%d peers to go round-robin for %s", n, (dir==TR_UP?"upload":"download")); 210 while (n > 0) 211 { 212 const int i = tr_cryptoWeakRandInt (n); /* pick a peer at random */ 213 214 /* value of 3000 bytes chosen so that when using uTP we'll send a full-size 215 * frame right away and leave enough buffered data for the next frame to go 216 * out in a timely manner. */ 217 const size_t increment = 3000; 218 219 const int bytesUsed = tr_peerIoFlush (peers[i], dir, increment); 220 221 dbgmsg ("peer #%d of %d used %d bytes in this pass", i, n, bytesUsed); 222 223 if (bytesUsed != (int)increment) { 224 /* peer is done writing for now; move it to the end of the list */ 225 tr_peerIo * pio = peers[i]; 226 peers[i] = peers[n-1]; 227 peers[n-1] = pio; 228 --n; 210 int n; 211 int peerCount = tr_ptrArraySize (peerArray); 212 struct tr_peerIo ** peers = (struct tr_peerIo**) tr_ptrArrayBase (peerArray); 213 214 /* First phase of IO. Tries to distribute bandwidth fairly to keep faster 215 * peers from starving the others. Loop through the peers, giving each a 216 * small chunk of bandwidth. Keep looping until we run out of bandwidth 217 * and/or peers that can use it */ 218 n = peerCount; 219 dbgmsg ("%d peers to go round-robin for %s", n, (dir==TR_UP?"upload":"download")); 220 while (n > 0) 221 { 222 const int i = tr_cryptoWeakRandInt (n); /* pick a peer at random */ 223 224 /* value of 3000 bytes chosen so that when using uTP we'll send a full-size 225 * frame right away and leave enough buffered data for the next frame to go 226 * out in a timely manner. */ 227 const size_t increment = 3000; 228 229 const int bytesUsed = tr_peerIoFlush (peers[i], dir, increment); 230 231 dbgmsg ("peer #%d of %d used %d bytes in this pass", i, n, bytesUsed); 232 233 if (bytesUsed != (int)increment) 234 { 235 /* peer is done writing for now; move it to the end of the list */ 236 tr_peerIo * pio = peers[i]; 237 peers[i] = peers[n-1]; 238 peers[n-1] = pio; 239 --n; 229 240 } 230 241 } … … 236 247 unsigned int period_msec) 237 248 { 238 int i, peerCount; 239 tr_ptrArray tmp = TR_PTR_ARRAY_INIT; 240 tr_ptrArray low = TR_PTR_ARRAY_INIT; 241 tr_ptrArray high = TR_PTR_ARRAY_INIT; 242 tr_ptrArray normal = TR_PTR_ARRAY_INIT; 243 struct tr_peerIo ** peers; 244 245 /* allocateBandwidth () is a helper function with two purposes: 246 * 1. allocate bandwidth to b and its subtree 247 * 2. accumulate an array of all the peerIos from b and its subtree. */ 248 allocateBandwidth (b, TR_PRI_LOW, dir, period_msec, &tmp); 249 peers = (struct tr_peerIo**) tr_ptrArrayBase (&tmp); 250 peerCount = tr_ptrArraySize (&tmp); 251 252 for (i=0; i<peerCount; ++i) 253 { 254 tr_peerIo * io = peers[i]; 255 tr_peerIoRef (io); 256 257 tr_peerIoFlushOutgoingProtocolMsgs (io); 258 259 switch (io->priority) { 260 case TR_PRI_HIGH: tr_ptrArrayAppend (&high, io); /* fall through */ 261 case TR_PRI_NORMAL: tr_ptrArrayAppend (&normal, io); /* fall through */ 262 default: tr_ptrArrayAppend (&low, io); 249 int i, peerCount; 250 tr_ptrArray tmp = TR_PTR_ARRAY_INIT; 251 tr_ptrArray low = TR_PTR_ARRAY_INIT; 252 tr_ptrArray high = TR_PTR_ARRAY_INIT; 253 tr_ptrArray normal = TR_PTR_ARRAY_INIT; 254 struct tr_peerIo ** peers; 255 256 /* allocateBandwidth () is a helper function with two purposes: 257 * 1. allocate bandwidth to b and its subtree 258 * 2. accumulate an array of all the peerIos from b and its subtree. */ 259 allocateBandwidth (b, TR_PRI_LOW, dir, period_msec, &tmp); 260 peers = (struct tr_peerIo**) tr_ptrArrayBase (&tmp); 261 peerCount = tr_ptrArraySize (&tmp); 262 263 for (i=0; i<peerCount; ++i) 264 { 265 tr_peerIo * io = peers[i]; 266 tr_peerIoRef (io); 267 268 tr_peerIoFlushOutgoingProtocolMsgs (io); 269 270 switch (io->priority) 271 { 272 case TR_PRI_HIGH: tr_ptrArrayAppend (&high, io); /* fall through */ 273 case TR_PRI_NORMAL: tr_ptrArrayAppend (&normal, io); /* fall through */ 274 default: tr_ptrArrayAppend (&low, io); 263 275 } 264 276 } 265 277 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 278 /* First phase of IO. Tries to distribute bandwidth fairly to keep faster 279 * peers from starving the others. Loop through the peers, giving each a 280 * small chunk of bandwidth. Keep looping until we run out of bandwidth 281 * and/or peers that can use it */ 282 phaseOne (&high, dir); 283 phaseOne (&normal, dir); 284 phaseOne (&low, dir); 285 286 /* Second phase of IO. To help us scale in high bandwidth situations, 287 * enable on-demand IO for peers with bandwidth left to burn. 288 * This on-demand IO is enabled until (1) the peer runs out of bandwidth, 289 * or (2) the next tr_bandwidthAllocate () call, when we start over again. */ 290 for (i=0; i<peerCount; ++i) 291 tr_peerIoSetEnabled (peers[i], dir, tr_peerIoHasBandwidthLeft (peers[i], dir)); 292 293 for (i=0; i<peerCount; ++i) 294 tr_peerIoUnref (peers[i]); 295 296 /* cleanup */ 297 tr_ptrArrayDestruct (&normal, NULL); 298 tr_ptrArrayDestruct (&high, NULL); 299 tr_ptrArrayDestruct (&low, NULL); 300 tr_ptrArrayDestruct (&tmp, NULL); 289 301 } 290 302 … … 292 304 tr_bandwidthSetPeer (tr_bandwidth * b, tr_peerIo * peer) 293 305 { 294 295 296 297 306 assert (tr_isBandwidth (b)); 307 assert ((peer == NULL) || tr_isPeerIo (peer)); 308 309 b->peer = peer; 298 310 } 299 311 … … 308 320 unsigned int byteCount) 309 321 { 310 311 312 313 314 { 315 322 assert (tr_isBandwidth (b)); 323 assert (tr_isDirection (dir)); 324 325 if (b) 326 { 327 if (b->band[dir].isLimited) 316 328 { 317 318 319 320 321 329 byteCount = MIN (byteCount, b->band[dir].bytesLeft); 330 331 /* if we're getting close to exceeding the speed limit, 332 * clamp down harder on the bytes available */ 333 if (byteCount > 0) 322 334 { 323 324 325 326 327 328 329 330 331 332 333 334 335 336 335 double current; 336 double desired; 337 double r; 338 339 if (now == 0) 340 now = tr_time_msec (); 341 342 current = tr_bandwidthGetRawSpeed_Bps (b, now, TR_DOWN); 343 desired = tr_bandwidthGetDesiredSpeed_Bps (b, TR_DOWN); 344 r = desired >= 1 ? current / desired : 0; 345 346 if (r > 1.0) byteCount = 0; 347 else if (r > 0.9) byteCount *= 0.8; 348 else if (r > 0.8) byteCount *= 0.9; 337 349 } 338 350 } 339 351 340 341 342 } 343 344 352 if (b->parent && b->band[dir].honorParentLimits && (byteCount > 0)) 353 byteCount = bandwidthClamp (b->parent, now, dir, byteCount); 354 } 355 356 return byteCount; 345 357 } 346 358 unsigned int … … 349 361 unsigned int byteCount) 350 362 { 351 363 return bandwidthClamp (b, 0, dir, byteCount); 352 364 } 353 365 … … 356 368 tr_bandwidthGetRawSpeed_Bps (const tr_bandwidth * b, const uint64_t now, const tr_direction dir) 357 369 { 358 359 360 361 370 assert (tr_isBandwidth (b)); 371 assert (tr_isDirection (dir)); 372 373 return getSpeed_Bps (&b->band[dir].raw, HISTORY_MSEC, now); 362 374 } 363 375 … … 365 377 tr_bandwidthGetPieceSpeed_Bps (const tr_bandwidth * b, const uint64_t now, const tr_direction dir) 366 378 { 367 368 369 370 379 assert (tr_isBandwidth (b)); 380 assert (tr_isDirection (dir)); 381 382 return getSpeed_Bps (&b->band[dir].piece, HISTORY_MSEC, now); 371 383 } 372 384 … … 375 387 tr_direction dir, 376 388 size_t byteCount, 377 bool isPieceData,389 bool isPieceData, 378 390 uint64_t now) 379 391 { 380 381 382 383 384 385 386 387 388 392 struct tr_band * band; 393 394 assert (tr_isBandwidth (b)); 395 assert (tr_isDirection (dir)); 396 397 band = &b->band[dir]; 398 399 if (band->isLimited && isPieceData) 400 band->bytesLeft -= MIN (band->bytesLeft, byteCount); 389 401 390 402 #ifdef DEBUG_DIRECTION … … 394 406 #endif 395 407 396 397 398 399 400 401 402 403 } 408 bytesUsed (now, &band->raw, byteCount); 409 410 if (isPieceData) 411 bytesUsed (now, &band->piece, byteCount); 412 413 if (b->parent != NULL) 414 tr_bandwidthUsed (b->parent, dir, byteCount, isPieceData, now); 415 } -
trunk/libtransmission/crypto.c
r13625 r13863 38 38 tr_sha1 (uint8_t * setme, const void * content1, int content1_len, ...) 39 39 { 40 41 42 43 44 45 46 47 48 49 50 51 52 40 va_list vl; 41 SHA_CTX sha; 42 const void * content; 43 44 SHA1_Init (&sha); 45 SHA1_Update (&sha, content1, content1_len); 46 47 va_start (vl, content1_len); 48 while ((content = va_arg (vl, const void*))) 49 SHA1_Update (&sha, content, va_arg (vl, int)); 50 va_end (vl); 51 52 SHA1_Final (setme, &sha); 53 53 } 54 54 … … 66 66 static const uint8_t dh_P[PRIME_LEN] = 67 67 { 68 69 70 71 72 73 74 75 68 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 69 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 70 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 71 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 72 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 73 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 74 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 75 0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63, 76 76 }; 77 77 … … 83 83 84 84 #define logErrorFromSSL(...) \ 85 86 87 88 89 90 91 85 do { \ 86 if (tr_msgLoggingIsActive (TR_MSG_ERR)) { \ 87 char buf[512]; \ 88 ERR_error_string_n (ERR_get_error (), buf, sizeof (buf)); \ 89 tr_msg (__FILE__, __LINE__, TR_MSG_ERR, MY_NAME, "%s", buf); \ 90 } \ 91 } while (0) 92 92 93 93 static void 94 94 ensureKeyExists (tr_crypto * crypto) 95 95 { 96 if (crypto->dh == NULL) 97 { 98 int len, offset; 99 DH * dh = DH_new (); 100 101 dh->p = BN_bin2bn (dh_P, sizeof (dh_P), NULL); 102 if (dh->p == NULL) 96 if (crypto->dh == NULL) 97 { 98 int len, offset; 99 DH * dh = DH_new (); 100 101 dh->p = BN_bin2bn (dh_P, sizeof (dh_P), NULL); 102 if (dh->p == NULL) 103 logErrorFromSSL (); 104 105 dh->g = BN_bin2bn (dh_G, sizeof (dh_G), NULL); 106 if (dh->g == NULL) 107 logErrorFromSSL (); 108 109 /* private DH value: strong random BN of DH_PRIVKEY_LEN*8 bits */ 110 dh->priv_key = BN_new (); 111 do 112 { 113 if (BN_rand (dh->priv_key, DH_PRIVKEY_LEN * 8, -1, 0) != 1) 103 114 logErrorFromSSL (); 104 105 dh->g = BN_bin2bn (dh_G, sizeof (dh_G), NULL); 106 if (dh->g == NULL) 107 logErrorFromSSL (); 108 109 /* private DH value: strong random BN of DH_PRIVKEY_LEN*8 bits */ 110 dh->priv_key = BN_new (); 111 do { 112 if (BN_rand (dh->priv_key, DH_PRIVKEY_LEN * 8, -1, 0) != 1) 113 logErrorFromSSL (); 114 } while (BN_num_bits (dh->priv_key) < DH_PRIVKEY_LEN_MIN * 8); 115 116 if (!DH_generate_key (dh)) 117 logErrorFromSSL (); 118 119 /* DH can generate key sizes that are smaller than the size of 120 P with exponentially decreasing probability, in which case 121 the msb's of myPublicKey need to be zeroed appropriately. */ 122 len = BN_num_bytes (dh->pub_key); 123 offset = KEY_LEN - len; 124 assert (len <= KEY_LEN); 125 memset (crypto->myPublicKey, 0, offset); 126 BN_bn2bin (dh->pub_key, crypto->myPublicKey + offset); 127 128 crypto->dh = dh; 115 } 116 while (BN_num_bits (dh->priv_key) < DH_PRIVKEY_LEN_MIN * 8); 117 118 if (!DH_generate_key (dh)) 119 logErrorFromSSL (); 120 121 /* DH can generate key sizes that are smaller than the size of 122 P with exponentially decreasing probability, in which case 123 the msb's of myPublicKey need to be zeroed appropriately. */ 124 len = BN_num_bytes (dh->pub_key); 125 offset = KEY_LEN - len; 126 assert (len <= KEY_LEN); 127 memset (crypto->myPublicKey, 0, offset); 128 BN_bn2bin (dh->pub_key, crypto->myPublicKey + offset); 129 130 crypto->dh = dh; 129 131 } 130 132 } … … 133 135 tr_cryptoConstruct (tr_crypto * crypto, const uint8_t * torrentHash, bool isIncoming) 134 136 { 135 136 137 138 139 137 memset (crypto, 0, sizeof (tr_crypto)); 138 139 crypto->dh = NULL; 140 crypto->isIncoming = isIncoming; 141 tr_cryptoSetTorrentHash (crypto, torrentHash); 140 142 } 141 143 … … 143 145 tr_cryptoDestruct (tr_crypto * crypto) 144 146 { 145 146 147 if (crypto->dh != NULL) 148 DH_free (crypto->dh); 147 149 } 148 150 … … 155 157 const uint8_t * peerPublicKey) 156 158 { 157 int len; 158 uint8_t secret[KEY_LEN]; 159 BIGNUM * bn = BN_bin2bn (peerPublicKey, KEY_LEN, NULL); 160 DH * dh; 161 162 ensureKeyExists (crypto); 163 dh = crypto->dh; 164 165 assert (DH_size (dh) == KEY_LEN); 166 167 len = DH_compute_key (secret, bn, dh); 168 if (len == -1) 169 logErrorFromSSL (); 170 else { 171 int offset; 172 assert (len <= KEY_LEN); 173 offset = KEY_LEN - len; 174 memset (crypto->mySecret, 0, offset); 175 memcpy (crypto->mySecret + offset, secret, len); 176 crypto->mySecretIsSet = 1; 177 } 178 179 BN_free (bn); 180 return crypto->mySecret; 159 DH * dh; 160 int len; 161 uint8_t secret[KEY_LEN]; 162 BIGNUM * bn = BN_bin2bn (peerPublicKey, KEY_LEN, NULL); 163 164 ensureKeyExists (crypto); 165 dh = crypto->dh; 166 167 assert (DH_size (dh) == KEY_LEN); 168 169 len = DH_compute_key (secret, bn, dh); 170 if (len == -1) 171 { 172 logErrorFromSSL (); 173 } 174 else 175 { 176 int offset; 177 assert (len <= KEY_LEN); 178 offset = KEY_LEN - len; 179 memset (crypto->mySecret, 0, offset); 180 memcpy (crypto->mySecret + offset, secret, len); 181 crypto->mySecretIsSet = 1; 182 } 183 184 BN_free (bn); 185 return crypto->mySecret; 181 186 } 182 187 183 188 const uint8_t* 184 189 tr_cryptoGetMyPublicKey (const tr_crypto * crypto, 185 int *setme_len)186 { 187 188 189 190 int * setme_len) 191 { 192 ensureKeyExists ((tr_crypto *) crypto); 193 *setme_len = KEY_LEN; 194 return crypto->myPublicKey; 190 195 } 191 196 … … 195 200 196 201 static void 197 initRC4 (tr_crypto *crypto,198 RC4_KEY *setme,202 initRC4 (tr_crypto * crypto, 203 RC4_KEY * setme, 199 204 const char * key) 200 205 { 201 202 203 204 205 206 207 208 209 210 211 212 { 213 214 } 215 216 { 217 206 SHA_CTX sha; 207 uint8_t buf[SHA_DIGEST_LENGTH]; 208 209 assert (crypto->torrentHashIsSet); 210 assert (crypto->mySecretIsSet); 211 212 if (SHA1_Init (&sha) 213 && SHA1_Update (&sha, key, 4) 214 && SHA1_Update (&sha, crypto->mySecret, KEY_LEN) 215 && SHA1_Update (&sha, crypto->torrentHash, SHA_DIGEST_LENGTH) 216 && SHA1_Final (buf, &sha)) 217 { 218 RC4_set_key (setme, SHA_DIGEST_LENGTH, buf); 219 } 220 else 221 { 222 logErrorFromSSL (); 218 223 } 219 224 } … … 222 227 tr_cryptoDecryptInit (tr_crypto * crypto) 223 228 { 224 225 const char *txt = crypto->isIncoming ? "keyA" : "keyB";226 227 228 229 } 230 231 void 232 tr_cryptoDecrypt (tr_crypto *crypto,229 unsigned char discard[1024]; 230 const char * txt = crypto->isIncoming ? "keyA" : "keyB"; 231 232 initRC4 (crypto, &crypto->dec_key, txt); 233 RC4 (&crypto->dec_key, sizeof (discard), discard, discard); 234 } 235 236 void 237 tr_cryptoDecrypt (tr_crypto * crypto, 233 238 size_t buf_len, 234 239 const void * buf_in, 235 void *buf_out)236 { 237 240 void * buf_out) 241 { 242 RC4 (&crypto->dec_key, buf_len, 238 243 (const unsigned char*)buf_in, 239 244 (unsigned char*)buf_out); … … 243 248 tr_cryptoEncryptInit (tr_crypto * crypto) 244 249 { 245 246 const char *txt = crypto->isIncoming ? "keyB" : "keyA";247 248 249 250 } 251 252 void 253 tr_cryptoEncrypt (tr_crypto *crypto,250 unsigned char discard[1024]; 251 const char * txt = crypto->isIncoming ? "keyB" : "keyA"; 252 253 initRC4 (crypto, &crypto->enc_key, txt); 254 RC4 (&crypto->enc_key, sizeof (discard), discard, discard); 255 } 256 257 void 258 tr_cryptoEncrypt (tr_crypto * crypto, 254 259 size_t buf_len, 255 260 const void * buf_in, 256 void *buf_out)257 { 258 261 void * buf_out) 262 { 263 RC4 (&crypto->enc_key, buf_len, 259 264 (const unsigned char*)buf_in, 260 265 (unsigned char*)buf_out); … … 266 271 267 272 void 268 tr_cryptoSetTorrentHash (tr_crypto *crypto,273 tr_cryptoSetTorrentHash (tr_crypto * crypto, 269 274 const uint8_t * hash) 270 275 { 271 272 273 274 275 276 276 crypto->torrentHashIsSet = hash ? 1 : 0; 277 278 if (hash) 279 memcpy (crypto->torrentHash, hash, SHA_DIGEST_LENGTH); 280 else 281 memset (crypto->torrentHash, 0, SHA_DIGEST_LENGTH); 277 282 } 278 283 … … 280 285 tr_cryptoGetTorrentHash (const tr_crypto * crypto) 281 286 { 282 283 284 285 287 assert (crypto); 288 assert (crypto->torrentHashIsSet); 289 290 return crypto->torrentHash; 286 291 } 287 292 … … 289 294 tr_cryptoHasTorrentHash (const tr_crypto * crypto) 290 295 { 291 292 293 296 assert (crypto); 297 298 return crypto->torrentHashIsSet ? 1 : 0; 294 299 } 295 300 … … 297 302 tr_cryptoRandInt (int upperBound) 298 303 { 299 300 301 302 303 304 305 { 306 307 } 308 309 { 310 311 } 312 313 304 int noise; 305 int val; 306 307 assert (upperBound > 0); 308 309 if (RAND_pseudo_bytes ((unsigned char *) &noise, sizeof noise) >= 0) 310 { 311 val = abs (noise) % upperBound; 312 } 313 else /* fall back to a weaker implementation... */ 314 { 315 val = tr_cryptoWeakRandInt (upperBound); 316 } 317 318 return val; 314 319 } 315 320 … … 317 322 tr_cryptoWeakRandInt (int upperBound) 318 323 { 319 320 321 322 323 324 { 325 326 327 } 328 329 324 static bool init = false; 325 326 assert (upperBound > 0); 327 328 if (!init) 329 { 330 srand (tr_time_msec ()); 331 init = true; 332 } 333 334 return rand () % upperBound; 330 335 } 331 336 … … 333 338 tr_cryptoRandBuf (void * buf, size_t len) 334 339 { 335 336 340 if (RAND_pseudo_bytes ((unsigned char*)buf, len) != 1) 341 logErrorFromSSL (); 337 342 } 338 343 … … 344 349 tr_ssha1 (const void * plaintext) 345 350 { 346 enum { saltval_len = 8, 347 salter_len = 64 }; 348 static const char * salter = "0123456789" 349 "abcdefghijklmnopqrstuvwxyz" 350 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 351 "./"; 352 353 size_t i; 354 unsigned char salt[saltval_len]; 355 uint8_t sha[SHA_DIGEST_LENGTH]; 356 char buf[2*SHA_DIGEST_LENGTH + saltval_len + 2]; 357 358 tr_cryptoRandBuf (salt, saltval_len); 359 for (i=0; i<saltval_len; ++i) 360 salt[i] = salter[ salt[i] % salter_len ]; 361 362 tr_sha1 (sha, plaintext, strlen (plaintext), salt, saltval_len, NULL); 363 tr_sha1_to_hex (&buf[1], sha); 364 memcpy (&buf[1+2*SHA_DIGEST_LENGTH], &salt, saltval_len); 365 buf[1+2*SHA_DIGEST_LENGTH + saltval_len] = '\0'; 366 buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring 367 easier */ 368 369 return tr_strdup (&buf); 351 enum { saltval_len = 8, 352 salter_len = 64 }; 353 static const char * salter = "0123456789" 354 "abcdefghijklmnopqrstuvwxyz" 355 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 356 "./"; 357 358 size_t i; 359 unsigned char salt[saltval_len]; 360 uint8_t sha[SHA_DIGEST_LENGTH]; 361 char buf[2*SHA_DIGEST_LENGTH + saltval_len + 2]; 362 363 tr_cryptoRandBuf (salt, saltval_len); 364 for (i=0; i<saltval_len; ++i) 365 salt[i] = salter[ salt[i] % salter_len ]; 366 367 tr_sha1 (sha, plaintext, strlen (plaintext), salt, saltval_len, NULL); 368 tr_sha1_to_hex (&buf[1], sha); 369 memcpy (&buf[1+2*SHA_DIGEST_LENGTH], &salt, saltval_len); 370 buf[1+2*SHA_DIGEST_LENGTH + saltval_len] = '\0'; 371 buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring easier */ 372 373 return tr_strdup (&buf); 370 374 } 371 375 … … 373 377 tr_ssha1_matches (const char * source, const char * pass) 374 378 { 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 } 379 char * salt; 380 size_t saltlen; 381 char * hashed; 382 uint8_t buf[SHA_DIGEST_LENGTH]; 383 bool result; 384 const size_t sourcelen = strlen (source); 385 386 /* extract the salt */ 387 if (sourcelen < 2*SHA_DIGEST_LENGTH-1) 388 return false; 389 saltlen = sourcelen - 2*SHA_DIGEST_LENGTH-1; 390 salt = tr_malloc (saltlen); 391 memcpy (salt, source + 2*SHA_DIGEST_LENGTH+1, saltlen); 392 393 /* hash pass + salt */ 394 hashed = tr_malloc (2*SHA_DIGEST_LENGTH + saltlen + 2); 395 tr_sha1 (buf, pass, strlen (pass), salt, saltlen, NULL); 396 tr_sha1_to_hex (&hashed[1], buf); 397 memcpy (hashed + 1+2*SHA_DIGEST_LENGTH, salt, saltlen); 398 hashed[1+2*SHA_DIGEST_LENGTH + saltlen] = '\0'; 399 hashed[0] = '{'; 400 401 result = strcmp (source, hashed) == 0 ? true : false; 402 403 tr_free (hashed); 404 tr_free (salt); 405 406 return result; 407 } -
trunk/libtransmission/peer-mgr.c
r13801 r13863 44 44 enum 45 45 { 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 46 /* how frequently to cull old atoms */ 47 ATOM_PERIOD_MSEC = (60 * 1000), 48 49 /* how frequently to change which peers are choked */ 50 RECHOKE_PERIOD_MSEC = (10 * 1000), 51 52 /* an optimistically unchoked peer is immune from rechoking 53 for this many calls to rechokeUploads (). */ 54 OPTIMISTIC_UNCHOKE_MULTIPLIER = 4, 55 56 /* how frequently to reallocate bandwidth */ 57 BANDWIDTH_PERIOD_MSEC = 500, 58 59 /* how frequently to age out old piece request lists */ 60 REFILL_UPKEEP_PERIOD_MSEC = (10 * 1000), 61 62 /* how frequently to decide which peers live and die */ 63 RECONNECT_PERIOD_MSEC = 500, 64 65 /* when many peers are available, keep idle ones this long */ 66 MIN_UPLOAD_IDLE_SECS = (60), 67 68 /* when few peers are available, keep idle ones this long */ 69 MAX_UPLOAD_IDLE_SECS = (60 * 5), 70 71 /* max number of peers to ask for per second overall. 72 * this throttle is to avoid overloading the router */ 73 MAX_CONNECTIONS_PER_SECOND = 12, 74 75 MAX_CONNECTIONS_PER_PULSE = (int)(MAX_CONNECTIONS_PER_SECOND * (RECONNECT_PERIOD_MSEC/1000.0)), 76 77 /* number of bad pieces a peer is allowed to send before we ban them */ 78 MAX_BAD_PIECES_PER_PEER = 5, 79 80 /* amount of time to keep a list of request pieces lying around 81 before it's considered too old and needs to be rebuilt */ 82 PIECE_LIST_SHELF_LIFE_SECS = 60, 83 84 /* use for bitwise operations w/peer_atom.flags2 */ 85 MYFLAG_BANNED = 1, 86 87 /* use for bitwise operations w/peer_atom.flags2 */ 88 /* unreachable for now... but not banned. 89 * if they try to connect to us it's okay */ 90 MYFLAG_UNREACHABLE = 2, 91 92 /* the minimum we'll wait before attempting to reconnect to a peer */ 93 MINIMUM_RECONNECT_INTERVAL_SECS = 5, 94 95 /** how long we'll let requests we've made linger before we cancel them */ 96 REQUEST_TTL_SECS = 90, 97 98 NO_BLOCKS_CANCEL_HISTORY = 120, 99 100 CANCEL_HISTORY_SEC = 60 101 101 }; 102 102 … … 118 118 struct peer_atom 119 119 { 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 120 uint8_t fromFirst; /* where the peer was first found */ 121 uint8_t fromBest; /* the "best" value of where the peer has been found */ 122 uint8_t flags; /* these match the added_f flags */ 123 uint8_t flags2; /* flags that aren't defined in added_f */ 124 int8_t seedProbability; /* how likely is this to be a seed... [0..100] or -1 for unknown */ 125 int8_t blocklisted; /* -1 for unknown, true for blocklisted, false for not blocklisted */ 126 127 tr_port port; 128 bool utp_failed; /* We recently failed to connect over uTP */ 129 uint16_t numFails; 130 time_t time; /* when the peer's connection status last changed */ 131 time_t piece_data_time; 132 133 time_t lastConnectionAttemptAt; 134 time_t lastConnectionAt; 135 136 /* similar to a TTL field, but less rigid -- 137 * if the swarm is small, the atom will be kept past this date. */ 138 time_t shelf_date; 139 tr_peer * peer; /* will be NULL if not connected */ 140 tr_address addr; 141 141 }; 142 142 … … 147 147 tr_isAtom (const struct peer_atom * atom) 148 148 { 149 150 151 152 149 return (atom != NULL) 150 && (atom->fromFirst < TR_PEER_FROM__MAX) 151 && (atom->fromBest < TR_PEER_FROM__MAX) 152 && (tr_address_is_valid (&atom->addr)); 153 153 } 154 154 #endif … … 157 157 tr_atomAddrStr (const struct peer_atom * atom) 158 158 { 159 159 return atom ? tr_peerIoAddrStr (&atom->addr, atom->port) : "[no atom]"; 160 160 } 161 161 162 162 struct block_request 163 163 { 164 165 166 164 tr_block_index_t block; 165 tr_peer * peer; 166 time_t sentAt; 167 167 }; 168 168 169 169 struct weighted_piece 170 170 { 171 172 173 171 tr_piece_index_t index; 172 int16_t salt; 173 int16_t requestCount; 174 174 }; 175 175 176 176 enum piece_sort_state 177 177 { 178 179 180 178 PIECES_UNSORTED, 179 PIECES_SORTED_BY_INDEX, 180 PIECES_SORTED_BY_WEIGHT 181 181 }; 182 182 … … 184 184 typedef struct tr_torrent_peers 185 185 { 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 186 tr_ptrArray outgoingHandshakes; /* tr_handshake */ 187 tr_ptrArray pool; /* struct peer_atom */ 188 tr_ptrArray peers; /* tr_peer */ 189 tr_ptrArray webseeds; /* tr_webseed */ 190 191 tr_torrent * tor; 192 struct tr_peerMgr * manager; 193 194 tr_peer * optimistic; /* the optimistic peer, or NULL if none */ 195 int optimisticUnchokeTimeScaler; 196 197 bool isRunning; 198 bool needsCompletenessCheck; 199 200 struct block_request * requests; 201 int requestCount; 202 int requestAlloc; 203 204 struct weighted_piece * pieces; 205 int pieceCount; 206 enum piece_sort_state pieceSortState; 207 208 /* An array of pieceCount items stating how many peers have each piece. 209 This is used to help us for downloading pieces "rarest first." 210 This may be NULL if we don't have metainfo yet, or if we're not 211 downloading and don't care about rarity */ 212 uint16_t * pieceReplication; 213 size_t pieceReplicationSize; 214 215 int interestedCount; 216 int maxPeers; 217 time_t lastCancel; 218 219 /* Before the endgame this should be 0. In endgame, is contains the average 220 * number of pending requests per peer. Only peers which have more pending 221 * requests are considered 'fast' are allowed to request a block that's 222 * already been requested from another (slower?) peer. */ 223 int endgame; 224 224 } 225 225 Torrent; … … 227 227 struct tr_peerMgr 228 228 { 229 230 231 232 233 234 229 tr_session * session; 230 tr_ptrArray incomingHandshakes; /* tr_handshake */ 231 struct event * bandwidthTimer; 232 struct event * rechokeTimer; 233 struct event * refillUpkeepTimer; 234 struct event * atomTimer; 235 235 }; 236 236 … … 258 258 managerLock (const struct tr_peerMgr * manager) 259 259 { 260 260 tr_sessionLock (manager->session); 261 261 } 262 262 … … 264 264 managerUnlock (const struct tr_peerMgr * manager) 265 265 { 266 266 tr_sessionUnlock (manager->session); 267 267 } 268 268 … … 270 270 torrentLock (Torrent * torrent) 271 271 { 272 272 managerLock (torrent->manager); 273 273 } 274 274 … … 276 276 torrentUnlock (Torrent * torrent) 277 277 { 278 278 managerUnlock (torrent->manager); 279 279 } 280 280 … … 282 282 torrentIsLocked (const Torrent * t) 283 283 { 284 284 return tr_sessionIsLocked (t->manager->session); 285 285 } 286 286 … … 292 292 handshakeCompareToAddr (const void * va, const void * vb) 293 293 { 294 295 296 294 const tr_handshake * a = va; 295 296 return tr_address_compare (tr_handshakeGetAddr (a, NULL), vb); 297 297 } 298 298 … … 300 300 handshakeCompare (const void * a, const void * b) 301 301 { 302 302 return handshakeCompareToAddr (a, tr_handshakeGetAddr (b, NULL)); 303 303 } 304 304 … … 306 306 getExistingHandshake (tr_ptrArray * handshakes, const tr_address * addr) 307 307 { 308 309 310 311 308 if (tr_ptrArrayEmpty (handshakes)) 309 return NULL; 310 311 return tr_ptrArrayFindSorted (handshakes, addr, handshakeCompareToAddr); 312 312 } 313 313 … … 315 315 comparePeerAtomToAddress (const void * va, const void * vb) 316 316 { 317 318 319 317 const struct peer_atom * a = va; 318 319 return tr_address_compare (&a->addr, vb); 320 320 } 321 321 … … 323 323 compareAtomsByAddress (const void * va, const void * vb) 324 324 { 325 326 327 328 329 325 const struct peer_atom * b = vb; 326 327 assert (tr_isAtom (b)); 328 329 return comparePeerAtomToAddress (va, &b->addr); 330 330 } 331 331 … … 337 337 tr_peerAddress (const tr_peer * peer) 338 338 { 339 339 return &peer->atom->addr; 340 340 } 341 341 … … 344 344 const uint8_t * hash) 345 345 { 346 347 348 346 tr_torrent * tor = tr_torrentFindFromHash (manager->session, hash); 347 348 return tor == NULL ? NULL : tor->torrentPeers; 349 349 } 350 350 … … 352 352 peerCompare (const void * a, const void * b) 353 353 { 354 354 return tr_address_compare (tr_peerAddress (a), tr_peerAddress (b)); 355 355 } 356 356 … … 359 359 const tr_address * addr) 360 360 { 361 362 361 Torrent * tt = (Torrent*)t; 362 return tr_ptrArrayFindSorted (&tt->pool, addr, comparePeerAtomToAddress); 363 363 } 364 364 … … 366 366 peerIsInUse (const Torrent * ct, const struct peer_atom * atom) 367 367 { 368 369 370 371 372 373 374 368 Torrent * t = (Torrent*) ct; 369 370 assert (torrentIsLocked (t)); 371 372 return (atom->peer != NULL) 373 || getExistingHandshake (&t->outgoingHandshakes, &atom->addr) 374 || getExistingHandshake (&t->manager->incomingHandshakes, &atom->addr); 375 375 } 376 376 … … 378 378 tr_peerConstruct (tr_peer * peer) 379 379 { 380 381 382 380 memset (peer, 0, sizeof (tr_peer)); 381 382 peer->have = TR_BITFIELD_INIT; 383 383 } 384 384 … … 386 386 peerNew (struct peer_atom * atom) 387 387 { 388 389 390 391 392 393 394 388 tr_peer * peer = tr_new (tr_peer, 1); 389 tr_peerConstruct (peer); 390 391 peer->atom = atom; 392 atom->peer = peer; 393 394 return peer; 395 395 } 396 396 … … 398 398 getPeer (Torrent * torrent, struct peer_atom * atom) 399 399 { 400 401 402 403 404 405 406 407 { 408 409 410 411 412 } 413 414 400 tr_peer * peer; 401 402 assert (torrentIsLocked (torrent)); 403 404 peer = atom->peer; 405 406 if (peer == NULL) 407 { 408 peer = peerNew (atom); 409 tr_bitfieldConstruct (&peer->have, torrent->tor->info.pieceCount); 410 tr_bitfieldConstruct (&peer->blame, torrent->tor->blockCount); 411 tr_ptrArrayInsertSorted (&torrent->peers, peer, peerCompare); 412 } 413 414 return peer; 415 415 } 416 416 … … 420 420 tr_peerDestruct (tr_torrent * tor, tr_peer * peer) 421 421 { 422 assert (peer != NULL); 423 424 peerDeclinedAllRequests (tor->torrentPeers, peer); 425 426 if (peer->msgs != NULL) 427 tr_peerMsgsFree (peer->msgs); 428 429 if (peer->io) { 430 tr_peerIoClear (peer->io); 431 tr_peerIoUnref (peer->io); /* balanced by the ref in handshakeDoneCB () */ 432 } 433 434 tr_bitfieldDestruct (&peer->have); 435 tr_bitfieldDestruct (&peer->blame); 436 437 if (peer->atom) 438 peer->atom->peer = NULL; 422 assert (peer != NULL); 423 424 peerDeclinedAllRequests (tor->torrentPeers, peer); 425 426 if (peer->msgs != NULL) 427 tr_peerMsgsFree (peer->msgs); 428 429 if (peer->io) 430 { 431 tr_peerIoClear (peer->io); 432 tr_peerIoUnref (peer->io); /* balanced by the ref in handshakeDoneCB () */ 433 } 434 435 tr_bitfieldDestruct (&peer->have); 436 tr_bitfieldDestruct (&peer->blame); 437 438 if (peer->atom) 439 peer->atom->peer = NULL; 439 440 } 440 441 … … 442 443 peerDelete (Torrent * t, tr_peer * peer) 443 444 { 444 445 445 tr_peerDestruct (t->tor, peer); 446 tr_free (peer); 446 447 } 447 448 … … 449 450 replicationExists (const Torrent * t) 450 451 { 451 452 return t->pieceReplication != NULL; 452 453 } 453 454 … … 455 456 replicationFree (Torrent * t) 456 457 { 457 458 459 458 tr_free (t->pieceReplication); 459 t->pieceReplication = NULL; 460 t->pieceReplicationSize = 0; 460 461 } 461 462 … … 463 464 replicationNew (Torrent * t) 464 465 { 465 466 467 468 469 470 471 472 473 474 475 476 { 477 478 479 480 481 482 483 484 466 tr_piece_index_t piece_i; 467 const tr_piece_index_t piece_count = t->tor->info.pieceCount; 468 tr_peer ** peers = (tr_peer**) tr_ptrArrayBase (&t->peers); 469 const int peer_count = tr_ptrArraySize (&t->peers); 470 471 assert (!replicationExists (t)); 472 473 t->pieceReplicationSize = piece_count; 474 t->pieceReplication = tr_new0 (uint16_t, piece_count); 475 476 for (piece_i=0; piece_i<piece_count; ++piece_i) 477 { 478 int peer_i; 479 uint16_t r = 0; 480 481 for (peer_i=0; peer_i<peer_count; ++peer_i) 482 if (tr_bitfieldHas (&peers[peer_i]->have, piece_i)) 483 ++r; 484 485 t->pieceReplication[piece_i] = r; 485 486 } 486 487 } … … 489 490 torrentFree (void * vt) 490 491 { 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 492 Torrent * t = vt; 493 494 assert (t); 495 assert (!t->isRunning); 496 assert (torrentIsLocked (t)); 497 assert (tr_ptrArrayEmpty (&t->outgoingHandshakes)); 498 assert (tr_ptrArrayEmpty (&t->peers)); 499 500 tr_ptrArrayDestruct (&t->webseeds, (PtrArrayForeachFunc)tr_webseedFree); 501 tr_ptrArrayDestruct (&t->pool, (PtrArrayForeachFunc)tr_free); 502 tr_ptrArrayDestruct (&t->outgoingHandshakes, NULL); 503 tr_ptrArrayDestruct (&t->peers, NULL); 504 505 replicationFree (t); 506 507 tr_free (t->requests); 508 tr_free (t->pieces); 509 tr_free (t); 509 510 } 510 511 … … 514 515 rebuildWebseedArray (Torrent * t, tr_torrent * tor) 515 516 { 516 517 518 519 520 521 522 523 524 525 { 526 527 517 unsigned int i; 518 const tr_info * inf = &tor->info; 519 520 /* clear the array */ 521 tr_ptrArrayDestruct (&t->webseeds, (PtrArrayForeachFunc)tr_webseedFree); 522 t->webseeds = TR_PTR_ARRAY_INIT; 523 524 /* repopulate it */ 525 for (i = 0; i < inf->webseedCount; ++i) 526 { 527 tr_webseed * w = tr_webseedNew (tor, inf->webseeds[i], peerCallbackFunc, t); 528 tr_ptrArrayAppend (&t->webseeds, w); 528 529 } 529 530 } … … 532 533 torrentNew (tr_peerMgr * manager, tr_torrent * tor) 533 534 { 534 535 536 537 538 539 540 541 542 543 544 545 546 535 Torrent * t; 536 537 t = tr_new0 (Torrent, 1); 538 t->manager = manager; 539 t->tor = tor; 540 t->pool = TR_PTR_ARRAY_INIT; 541 t->peers = TR_PTR_ARRAY_INIT; 542 t->webseeds = TR_PTR_ARRAY_INIT; 543 t->outgoingHandshakes = TR_PTR_ARRAY_INIT; 544 545 rebuildWebseedArray (t, tor); 546 547 return t; 547 548 } 548 549 … … 552 553 tr_peerMgrNew (tr_session * session) 553 554 { 554 555 556 557 558 555 tr_peerMgr * m = tr_new0 (tr_peerMgr, 1); 556 m->session = session; 557 m->incomingHandshakes = TR_PTR_ARRAY_INIT; 558 ensureMgrTimersExist (m); 559 return m; 559 560 } 560 561 … … 562 563 deleteTimer (struct event ** t) 563 564 { 564 565 { 566 567 565 if (*t != NULL) 566 { 567 event_free (*t); 568 *t = NULL; 568 569 } 569 570 } … … 572 573 deleteTimers (struct tr_peerMgr * m) 573 574 { 574 575 576 577 575 deleteTimer (&m->atomTimer); 576 deleteTimer (&m->bandwidthTimer); 577 deleteTimer (&m->rechokeTimer); 578 deleteTimer (&m->refillUpkeepTimer); 578 579 } 579 580 … … 581 582 tr_peerMgrFree (tr_peerMgr * manager) 582 583 { 583 584 585 586 587 588 589 590 591 592 593 594 595 584 managerLock (manager); 585 586 deleteTimers (manager); 587 588 /* free the handshakes. Abort invokes handshakeDoneCB (), which removes 589 * the item from manager->handshakes, so this is a little roundabout... */ 590 while (!tr_ptrArrayEmpty (&manager->incomingHandshakes)) 591 tr_handshakeAbort (tr_ptrArrayNth (&manager->incomingHandshakes, 0)); 592 593 tr_ptrArrayDestruct (&manager->incomingHandshakes, NULL); 594 595 managerUnlock (manager); 596 tr_free (manager); 596 597 } 597 598 … … 599 600 clientIsDownloadingFrom (const tr_torrent * tor, const tr_peer * peer) 600 601 { 601 602 603 604 602 if (!tr_torrentHasMetadata (tor)) 603 return true; 604 605 return peer->clientIsInterested && !peer->clientIsChoked; 605 606 } 606 607 … … 608 609 clientIsUploadingTo (const tr_peer * peer) 609 610 { 610 611 return peer->peerIsInterested && !peer->peerIsChoked; 611 612 } 612 613 … … 618 619 tr_peerMgrOnBlocklistChanged (tr_peerMgr * mgr) 619 620 { 620 tr_torrent * tor = NULL; 621 tr_session * session = mgr->session; 622 623 /* we cache whether or not a peer is blocklisted... 624 since the blocklist has changed, erase that cached value */ 625 while ((tor = tr_torrentNext (session, tor))) 626 { 627 int i; 628 Torrent * t = tor->torrentPeers; 629 const int n = tr_ptrArraySize (&t->pool); 630 for (i=0; i<n; ++i) { 631 struct peer_atom * atom = tr_ptrArrayNth (&t->pool, i); 632 atom->blocklisted = -1; 621 tr_torrent * tor = NULL; 622 tr_session * session = mgr->session; 623 624 /* we cache whether or not a peer is blocklisted... 625 since the blocklist has changed, erase that cached value */ 626 while ((tor = tr_torrentNext (session, tor))) 627 { 628 int i; 629 Torrent * t = tor->torrentPeers; 630 const int n = tr_ptrArraySize (&t->pool); 631 for (i=0; i<n; ++i) 632 { 633 struct peer_atom * atom = tr_ptrArrayNth (&t->pool, i); 634 atom->blocklisted = -1; 633 635 } 634 636 } … … 638 640 isAtomBlocklisted (tr_session * session, struct peer_atom * atom) 639 641 { 640 641 642 643 644 642 if (atom->blocklisted < 0) 643 atom->blocklisted = tr_sessionIsAddressBlocked (session, &atom->addr); 644 645 assert (tr_isBool (atom->blocklisted)); 646 return atom->blocklisted; 645 647 } 646 648 … … 653 655 atomSetSeedProbability (struct peer_atom * atom, int seedProbability) 654 656 { 655 656 657 658 659 660 661 662 663 657 assert (atom != NULL); 658 assert (-1<=seedProbability && seedProbability<=100); 659 660 atom->seedProbability = seedProbability; 661 662 if (seedProbability == 100) 663 atom->flags |= ADDED_F_SEED_FLAG; 664 else if (seedProbability != -1) 665 atom->flags &= ~ADDED_F_SEED_FLAG; 664 666 } 665 667 … … 667 669 atomIsSeed (const struct peer_atom * atom) 668 670 { 669 671 return atom->seedProbability == 100; 670 672 } 671 673 … … 673 675 atomSetSeed (const Torrent * t, struct peer_atom * atom) 674 676 { 675 676 { 677 678 679 677 if (!atomIsSeed (atom)) 678 { 679 tordbg (t, "marking peer %s as a seed", tr_atomAddrStr (atom)); 680 681 atomSetSeedProbability (atom, 100); 680 682 } 681 683 } … … 686 688 const tr_address * addr) 687 689 { 688 689 690 691 692 693 694 695 690 bool isSeed = false; 691 const Torrent * t = tor->torrentPeers; 692 const struct peer_atom * atom = getExistingAtom (t, addr); 693 694 if (atom) 695 isSeed = atomIsSeed (atom); 696 697 return isSeed; 696 698 } 697 699 … … 699 701 tr_peerMgrSetUtpSupported (tr_torrent * tor, const tr_address * addr) 700 702 { 701 702 703 704 703 struct peer_atom * atom = getExistingAtom (tor->torrentPeers, addr); 704 705 if (atom) 706 atom->flags |= ADDED_F_UTP_FLAGS; 705 707 } 706 708 … … 708 710 tr_peerMgrSetUtpFailed (tr_torrent *tor, const tr_address *addr, bool failed) 709 711 { 710 711 712 713 712 struct peer_atom * atom = getExistingAtom (tor->torrentPeers, addr); 713 714 if (atom) 715 atom->utp_failed = failed; 714 716 } 715 717 -
trunk/libtransmission/port-forwarding.c
r13631 r13863 33 33 struct tr_shared 34 34 { 35 boolisEnabled;36 boolisShuttingDown;37 booldoPortCheck;38 39 tr_port_forwardingnatpmpStatus;40 tr_port_forwardingupnpStatus;41 42 tr_upnp* upnp;43 tr_natpmp* natpmp;44 tr_session* session;45 46 struct event* timer;35 bool isEnabled; 36 bool isShuttingDown; 37 bool doPortCheck; 38 39 tr_port_forwarding natpmpStatus; 40 tr_port_forwarding upnpStatus; 41 42 tr_upnp * upnp; 43 tr_natpmp * natpmp; 44 tr_session * session; 45 46 struct event * timer; 47 47 }; 48 48 … … 54 54 getNatStateStr (int state) 55 55 { 56 57 { 58 59 60 61 62 56 switch (state) 57 { 58 case TR_PORT_MAPPING: return _("Starting"); 59 case TR_PORT_MAPPED: return _("Forwarded"); 60 case TR_PORT_UNMAPPING: return _("Stopping"); 61 case TR_PORT_UNMAPPED: return _("Not forwarded"); 62 default: return "???"; 63 63 } 64 64 } … … 67 67 natPulse (tr_shared * s, bool do_check) 68 68 { 69 const tr_port private_peer_port = s->session->private_peer_port; 70 const int is_enabled = s->isEnabled && !s->isShuttingDown; 71 tr_port public_peer_port; 72 int oldStatus; 73 int newStatus; 74 75 if (s->natpmp == NULL) 76 s->natpmp = tr_natpmpInit (); 77 if (s->upnp == NULL) 78 s->upnp = tr_upnpInit (); 79 80 oldStatus = tr_sharedTraversalStatus (s); 81 82 s->natpmpStatus = tr_natpmpPulse (s->natpmp, private_peer_port, is_enabled, &public_peer_port); 83 if (s->natpmpStatus == TR_PORT_MAPPED) 84 s->session->public_peer_port = public_peer_port; 85 86 s->upnpStatus = tr_upnpPulse (s->upnp, private_peer_port, is_enabled, do_check); 87 88 newStatus = tr_sharedTraversalStatus (s); 89 90 if (newStatus != oldStatus) 91 tr_ninf (getKey (), _("State changed from \"%1$s\" to \"%2$s\""), 92 getNatStateStr (oldStatus), 93 getNatStateStr (newStatus)); 69 int oldStatus; 70 int newStatus; 71 tr_port public_peer_port; 72 const tr_port private_peer_port = s->session->private_peer_port; 73 const int is_enabled = s->isEnabled && !s->isShuttingDown; 74 75 if (s->natpmp == NULL) 76 s->natpmp = tr_natpmpInit (); 77 78 if (s->upnp == NULL) 79 s->upnp = tr_upnpInit (); 80 81 oldStatus = tr_sharedTraversalStatus (s); 82 83 s->natpmpStatus = tr_natpmpPulse (s->natpmp, private_peer_port, is_enabled, &public_peer_port); 84 if (s->natpmpStatus == TR_PORT_MAPPED) 85 s->session->public_peer_port = public_peer_port; 86 87 s->upnpStatus = tr_upnpPulse (s->upnp, private_peer_port, is_enabled, do_check); 88 89 newStatus = tr_sharedTraversalStatus (s); 90 91 if (newStatus != oldStatus) 92 tr_ninf (getKey (), _("State changed from \"%1$s\" to \"%2$s\""), 93 getNatStateStr (oldStatus), 94 getNatStateStr (newStatus)); 94 95 } 95 96 … … 97 98 set_evtimer_from_status (tr_shared * s) 98 99 { 99 100 101 102 103 { 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 } 121 122 123 100 int sec=0, msec=0; 101 102 /* when to wake up again */ 103 switch (tr_sharedTraversalStatus (s)) 104 { 105 case TR_PORT_MAPPED: 106 /* if we're mapped, everything is fine... check back in 20 minutes 107 * to renew the port forwarding if it's expired */ 108 s->doPortCheck = true; 109 sec = 60 * 20; 110 break; 111 112 case TR_PORT_ERROR: 113 /* some kind of an error. wait 60 seconds and retry */ 114 sec = 60; 115 break; 116 117 default: 118 /* in progress. pulse frequently. */ 119 msec = 333000; 120 break; 121 } 122 123 if (s->timer != NULL) 124 tr_timerAdd (s->timer, sec, msec); 124 125 } 125 126 … … 127 128 onTimer (int fd UNUSED, short what UNUSED, void * vshared) 128 129 { 129 130 131 132 133 134 135 136 137 138 139 130 tr_shared * s = vshared; 131 132 assert (s); 133 assert (s->timer); 134 135 /* do something */ 136 natPulse (s, s->doPortCheck); 137 s->doPortCheck = false; 138 139 /* set up the timer for the next pulse */ 140 set_evtimer_from_status (s); 140 141 } 141 142 … … 147 148 tr_sharedInit (tr_session * session) 148 149 { 149 150 151 s->session= session;152 s->isEnabled= false;153 s->upnpStatus= TR_PORT_UNMAPPED;154 150 tr_shared * s = tr_new0 (tr_shared, 1); 151 152 s->session = session; 153 s->isEnabled = false; 154 s->upnpStatus = TR_PORT_UNMAPPED; 155 s->natpmpStatus = TR_PORT_UNMAPPED; 155 156 156 157 #if 0 157 158 { 159 160 161 158 if (isEnabled) 159 { 160 s->timer = tr_new0 (struct event, 1); 161 evtimer_set (s->timer, onTimer, s); 162 tr_timerAdd (s->timer, 0, 333000); 162 163 } 163 164 #endif 164 165 165 166 return s; 166 167 } 167 168 … … 169 170 stop_timer (tr_shared * s) 170 171 { 171 172 { 173 174 172 if (s->timer != NULL) 173 { 174 event_free (s->timer); 175 s->timer = NULL; 175 176 } 176 177 } … … 179 180 stop_forwarding (tr_shared * s) 180 181 { 181 182 183 184 185 186 187 188 189 190 191 192 182 tr_ninf (getKey (), "%s", _("Stopped")); 183 natPulse (s, false); 184 185 tr_natpmpClose (s->natpmp); 186 s->natpmp = NULL; 187 s->natpmpStatus = TR_PORT_UNMAPPED; 188 189 tr_upnpClose (s->upnp); 190 s->upnp = NULL; 191 s->upnpStatus = TR_PORT_UNMAPPED; 192 193 stop_timer (s); 193 194 } 194 195 … … 196 197 tr_sharedClose (tr_session * session) 197 198 { 198 199 200 201 202 203 199 tr_shared * s = session->shared; 200 201 s->isShuttingDown = true; 202 stop_forwarding (s); 203 s->session->shared = NULL; 204 tr_free (s); 204 205 } 205 206 … … 207 208 start_timer (tr_shared * s) 208 209 { 209 210 210 s->timer = evtimer_new (s->session->event_base, onTimer, s); 211 set_evtimer_from_status (s); 211 212 } 212 213 … … 214 215 tr_sharedTraversalEnable (tr_shared * s, bool isEnabled) 215 216 { 216 217 218 219 217 if ((s->isEnabled = isEnabled)) 218 start_timer (s); 219 else 220 stop_forwarding (s); 220 221 } 221 222 … … 223 224 tr_sharedPortChanged (tr_session * session) 224 225 { 225 226 227 228 { 229 230 231 226 tr_shared * s = session->shared; 227 228 if (s->isEnabled) 229 { 230 stop_timer (s); 231 natPulse (s, false); 232 start_timer (s); 232 233 } 233 234 } … … 236 237 tr_sharedTraversalIsEnabled (const tr_shared * s) 237 238 { 238 239 return s->isEnabled; 239 240 } 240 241 … … 242 243 tr_sharedTraversalStatus (const tr_shared * s) 243 244 { 244 245 } 245 return MAX (s->natpmpStatus, s->upnpStatus); 246 } -
trunk/libtransmission/utils.c
r13852 r13863 72 72 73 73 #ifndef WIN32 74 75 76 74 /* make null versions of these win32 functions */ 75 static inline int IsDebuggerPresent (void) { return false; } 76 static inline void OutputDebugString (const void * unused UNUSED) { } 77 77 #endif 78 78 … … 84 84 getMessageLock (void) 85 85 { 86 87 88 89 90 91 86 static tr_lock * l = NULL; 87 88 if (!l) 89 l = tr_lockNew (); 90 91 return l; 92 92 } 93 93 … … 95 95 tr_getLog (void) 96 96 { 97 static bool initialized = false; 98 static FILE * file = NULL; 99 100 if (!initialized) 101 { 102 const char * str = getenv ("TR_DEBUG_FD"); 103 int fd = 0; 104 if (str && *str) 105 fd = atoi (str); 106 switch (fd) 97 static bool initialized = false; 98 static FILE * file = NULL; 99 100 if (!initialized) 101 { 102 int fd = 0; 103 const char * str = getenv ("TR_DEBUG_FD"); 104 105 if (str && *str) 106 fd = atoi (str); 107 108 switch (fd) 107 109 { 108 case 1: 109 file = stdout; break; 110 111 case 2: 112 file = stderr; break; 113 114 default: 115 file = NULL; break; 110 case 1: 111 file = stdout; 112 break; 113 114 case 2: 115 file = stderr; 116 break; 117 118 default: 119 file = NULL; 120 break; 116 121 } 117 initialized = true; 118 } 119 120 return file; 122 123 initialized = true; 124 } 125 126 return file; 121 127 } 122 128 … … 130 136 tr_setMessageQueuing (bool enabled) 131 137 { 132 138 messageQueuing = enabled; 133 139 } 134 140 … … 136 142 tr_getMessageQueuing (void) 137 143 { 138 144 return messageQueuing != 0; 139 145 } 140 146 … … 142 148 tr_getQueuedMessages (void) 143 149 { 144 145 146 147 148 149 150 151 152 153 154 150 tr_msg_list * ret; 151 tr_lockLock (getMessageLock ()); 152 153 ret = messageQueue; 154 messageQueue = NULL; 155 messageQueueTail = &messageQueue; 156 157 messageQueueCount = 0; 158 159 tr_lockUnlock (getMessageLock ()); 160 return ret; 155 161 } 156 162 … … 158 164 tr_freeMessageList (tr_msg_list * list) 159 165 { 160 161 162 163 { 164 165 166 167 168 166 tr_msg_list * next; 167 168 while (NULL != list) 169 { 170 next = list->next; 171 free (list->message); 172 free (list->name); 173 free (list); 174 list = next; 169 175 } 170 176 } … … 178 184 { 179 185 #ifdef HAVE_LOCALTIME_R 180 186 return localtime_r (_clock, _result); 181 187 #else 182 183 184 185 188 struct tm *p = localtime (_clock); 189 if (p) 190 * (_result) = *p; 191 return p; 186 192 #endif 187 193 } … … 190 196 tr_getLogTimeStr (char * buf, int buflen) 191 197 { 192 chartmp[64];193 struct tmnow_tm;194 195 time_tseconds;196 intmilliseconds;197 198 199 200 201 202 203 204 205 206 198 char tmp[64]; 199 struct tm now_tm; 200 struct timeval tv; 201 time_t seconds; 202 int milliseconds; 203 204 gettimeofday (&tv, NULL); 205 206 seconds = tv.tv_sec; 207 tr_localtime_r (&seconds, &now_tm); 208 strftime (tmp, sizeof (tmp), "%H:%M:%S", &now_tm); 209 milliseconds = tv.tv_usec / 1000; 210 tr_snprintf (buf, buflen, "%s.%03d", tmp, milliseconds); 211 212 return buf; 207 213 } 208 214 … … 210 216 tr_deepLoggingIsActive (void) 211 217 { 212 213 214 215 216 217 218 static int8_t deepLoggingIsActive = -1; 219 220 if (deepLoggingIsActive < 0) 221 deepLoggingIsActive = IsDebuggerPresent () || (tr_getLog ()!=NULL); 222 223 return deepLoggingIsActive != 0; 218 224 } 219 225 … … 225 231 ...) 226 232 { 227 228 229 { 230 va_listargs;231 chartimestr[64];232 struct evbuffer * buf = evbuffer_new ();233 char * base = tr_basename (file);234 char * message;235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 233 FILE * fp = tr_getLog (); 234 if (fp || IsDebuggerPresent ()) 235 { 236 va_list args; 237 char timestr[64]; 238 char * message; 239 struct evbuffer * buf = evbuffer_new (); 240 char * base = tr_basename (file); 241 242 evbuffer_add_printf (buf, "[%s] ", 243 tr_getLogTimeStr (timestr, sizeof (timestr))); 244 if (name) 245 evbuffer_add_printf (buf, "%s ", name); 246 va_start (args, fmt); 247 evbuffer_add_vprintf (buf, fmt, args); 248 va_end (args); 249 evbuffer_add_printf (buf, " (%s:%d)\n", base, line); 250 /* FIXME (libevent2) ifdef this out for nonwindows platforms */ 251 message = evbuffer_free_to_str (buf); 252 OutputDebugString (message); 253 if (fp) 254 fputs (message, fp); 255 256 tr_free (message); 257 tr_free (base); 252 258 } 253 259 } … … 263 269 const char * fmt, ...) 264 270 { 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 { 280 271 const int err = errno; /* message logging shouldn't affect errno */ 272 char buf[1024]; 273 va_list ap; 274 tr_lockLock (getMessageLock ()); 275 276 /* build the text message */ 277 *buf = '\0'; 278 va_start (ap, fmt); 279 evutil_vsnprintf (buf, sizeof (buf), fmt, ap); 280 va_end (ap); 281 282 OutputDebugString (buf); 283 284 if (*buf) 285 { 286 if (messageQueuing) 281 287 { 282 283 284 285 286 287 288 289 290 291 292 293 294 295 288 tr_msg_list * newmsg; 289 newmsg = tr_new0 (tr_msg_list, 1); 290 newmsg->level = level; 291 newmsg->when = tr_time (); 292 newmsg->message = tr_strdup (buf); 293 newmsg->file = file; 294 newmsg->line = line; 295 newmsg->name = tr_strdup (name); 296 297 *messageQueueTail = newmsg; 298 messageQueueTail = &newmsg->next; 299 ++messageQueueCount; 300 301 if (messageQueueCount > TR_MAX_MSG_LOG) 296 302 { 297 tr_msg_list * old = messageQueue; 298 messageQueue = old->next; 299 old->next = NULL; 300 tr_freeMessageList (old); 301 302 --messageQueueCount; 303 304 assert (messageQueueCount == TR_MAX_MSG_LOG); 303 tr_msg_list * old = messageQueue; 304 messageQueue = old->next; 305 old->next = NULL; 306 tr_freeMessageList (old); 307 --messageQueueCount; 308 assert (messageQueueCount == TR_MAX_MSG_LOG); 305 309 } 306 310 } 307 311 else 308 312 { 309 char timestr[64];310 FILE * fp;311 312 313 314 315 316 317 318 319 320 321 322 313 FILE * fp; 314 char timestr[64]; 315 316 fp = tr_getLog (); 317 if (fp == NULL) 318 fp = stderr; 319 320 tr_getLogTimeStr (timestr, sizeof (timestr)); 321 322 if (name) 323 fprintf (fp, "[%s] %s: %s\n", timestr, name, buf); 324 else 325 fprintf (fp, "[%s] %s\n", timestr, buf); 326 fflush (fp); 323 327 } 324 328 } 325 329 326 327 330 tr_lockUnlock (getMessageLock ()); 331 errno = err; 328 332 } 329 333 … … 335 339 tr_malloc (size_t size) 336 340 { 337 341 return size ? malloc (size) : NULL; 338 342 } 339 343 … … 341 345 tr_malloc0 (size_t size) 342 346 { 343 347 return size ? calloc (1, size) : NULL; 344 348 } 345 349 … … 347 351 tr_free (void * p) 348 352 { 349 350 353 if (p != NULL) 354 free (p); 351 355 } 352 356 … … 354 358 tr_memdup (const void * src, size_t byteCount) 355 359 { 356 360 return memcpy (tr_malloc (byteCount), src, byteCount); 357 361 } 358 362 … … 364 368 tr_strip_positional_args (const char* str) 365 369 { 366 const char * in = str;367 368 369 const size_t len = str ? strlen (str) : 0;370 char * out;371 372 373 { 374 375 376 } 377 378 379 { 380 381 382 370 char * out; 371 static size_t bufsize = 0; 372 static char * buf = NULL; 373 const char * in = str; 374 const size_t len = str ? strlen (str) : 0; 375 376 if (!buf || (bufsize < len)) 377 { 378 bufsize = len * 2 + 1; 379 buf = tr_renew (char, buf, bufsize); 380 } 381 382 for (out = buf; str && *str; ++str) 383 { 384 *out++ = *str; 385 386 if ((*str == '%') && isdigit (str[1])) 383 387 { 384 385 386 387 388 388 const char * tmp = str + 1; 389 while (isdigit (*tmp)) 390 ++tmp; 391 if (*tmp == '$') 392 str = tmp[1]=='\'' ? tmp+1 : tmp; 389 393 } 390 394 391 392 393 394 } 395 *out = '\0'; 396 397 395 if ((*str == '%') && (str[1] == '\'')) 396 str = str + 1; 397 398 } 399 400 *out = '\0'; 401 return !in || strcmp (buf, in) ? buf : in; 398 402 } 399 403 … … 405 409 tr_timerAdd (struct event * timer, int seconds, int microseconds) 406 410 { 407 408 409 410 411 412 413 414 415 411 struct timeval tv; 412 tv.tv_sec = seconds; 413 tv.tv_usec = microseconds; 414 415 assert (tv.tv_sec >= 0); 416 assert (tv.tv_usec >= 0); 417 assert (tv.tv_usec < 1000000); 418 419 evtimer_add (timer, &tv); 416 420 } 417 421 … … 419 423 tr_timerAddMsec (struct event * timer, int msec) 420 424 { 421 422 423 425 const int seconds = msec / 1000; 426 const int usec = (msec%1000) * 1000; 427 tr_timerAdd (timer, seconds, usec); 424 428 } 425 429 … … 430 434 uint8_t * 431 435 tr_loadFile (const char * path, 432 size_t *size)433 { 434 435 436 437 438 439 440 441 442 443 { 444 445 446 447 448 } 449 450 451 { 452 453 454 455 } 456 457 458 459 460 { 461 462 463 464 465 } 466 467 468 { 469 470 471 472 473 474 } 475 476 477 { 478 479 480 481 482 483 484 } 485 486 487 488 489 436 size_t * size) 437 { 438 uint8_t * buf; 439 struct stat sb; 440 int fd; 441 ssize_t n; 442 const char * const err_fmt = _("Couldn't read \"%1$s\": %2$s"); 443 444 /* try to stat the file */ 445 errno = 0; 446 if (stat (path, &sb)) 447 { 448 const int err = errno; 449 tr_dbg (err_fmt, path, tr_strerror (errno)); 450 errno = err; 451 return NULL; 452 } 453 454 if ((sb.st_mode & S_IFMT) != S_IFREG) 455 { 456 tr_err (err_fmt, path, _("Not a regular file")); 457 errno = EISDIR; 458 return NULL; 459 } 460 461 /* Load the torrent file into our buffer */ 462 fd = tr_open_file_for_scanning (path); 463 if (fd < 0) 464 { 465 const int err = errno; 466 tr_err (err_fmt, path, tr_strerror (errno)); 467 errno = err; 468 return NULL; 469 } 470 buf = tr_malloc (sb.st_size + 1); 471 if (!buf) 472 { 473 const int err = errno; 474 tr_err (err_fmt, path, _("Memory allocation failed")); 475 tr_close_file (fd); 476 errno = err; 477 return NULL; 478 } 479 n = read (fd, buf, (size_t)sb.st_size); 480 if (n == -1) 481 { 482 const int err = errno; 483 tr_err (err_fmt, path, tr_strerror (errno)); 484 tr_close_file (fd); 485 free (buf); 486 errno = err; 487 return NULL; 488 } 489 490 tr_close_file (fd); 491 buf[ sb.st_size ] = '\0'; 492 *size = sb.st_size; 493 return buf; 490 494 } 491 495 … … 493 497 tr_basename (const char * path) 494 498 { 495 496 497 498 499 char * tmp = tr_strdup (path); 500 char * ret = tr_strdup (basename (tmp)); 501 tr_free (tmp); 502 return ret; 499 503 } 500 504 … … 502 506 tr_dirname (const char * path) 503 507 { 504 505 506 507 508 char * tmp = tr_strdup (path); 509 char * ret = tr_strdup (dirname (tmp)); 510 tr_free (tmp); 511 return ret; 508 512 } 509 513 … … 512 516 { 513 517 #ifdef HAVE_MKDTEMP 514 518 return mkdtemp (template); 515 519 #else 516 517 518 520 if (!mktemp (template) || mkdir (template, 0700)) 521 return NULL; 522 return template; 519 523 #endif 520 524 } … … 533 537 { 534 538 #ifdef WIN32 535 536 537 539 if (path && isalpha (path[0]) && path[1] == ':' && !path[2]) 540 return 0; 541 return mkdir (path); 538 542 #else 539 543 return mkdir (path, permissions); 540 544 #endif 541 545 } … … 545 549 int permissions) 546 550 { 547 char * path = tr_strdup (path_in); 548 char * p, * pp; 549 struct stat sb; 550 bool done; 551 int tmperr; 552 int rv; 553 554 /* walk past the root */ 555 p = path; 556 while (*p == TR_PATH_DELIMITER) 557 ++p; 558 559 pp = p; 560 done = false; 561 while ((p = strchr (pp, TR_PATH_DELIMITER)) || (p = strchr (pp, '\0'))) 562 { 563 if (!*p) 564 done = true; 565 else 566 *p = '\0'; 567 568 tmperr = errno; 569 rv = stat (path, &sb); 570 errno = tmperr; 571 if (rv) 551 char * p; 552 char * pp; 553 bool done; 554 int tmperr; 555 int rv; 556 struct stat sb; 557 char * path = tr_strdup (path_in); 558 559 /* walk past the root */ 560 p = path; 561 while (*p == TR_PATH_DELIMITER) 562 ++p; 563 564 pp = p; 565 done = false; 566 while ((p = strchr (pp, TR_PATH_DELIMITER)) || (p = strchr (pp, '\0'))) 567 { 568 if (!*p) 569 done = true; 570 else 571 *p = '\0'; 572 573 tmperr = errno; 574 rv = stat (path, &sb); 575 errno = tmperr; 576 if (rv) 572 577 { 573 574 578 /* Folder doesn't exist yet */ 579 if (tr_mkdir (path, permissions)) 575 580 { 576 577 578 579 580 581 tmperr = errno; 582 tr_err (_("Couldn't create \"%1$s\": %2$s"), path, tr_strerror (tmperr)); 583 tr_free (path); 584 errno = tmperr; 585 return -1; 581 586 } 582 587 } 583 588 else if ((sb.st_mode & S_IFMT) != S_IFDIR) 584 589 { 585 586 587 588 589 590 591 590 /* Node exists but isn't a folder */ 591 char * buf = tr_strdup_printf (_("File \"%s\" is in the way"), path); 592 tr_err (_("Couldn't create \"%1$s\": %2$s"), path_in, buf); 593 tr_free (buf); 594 tr_free (path); 595 errno = ENOTDIR; 596 return -1; 592 597 } 593 598 594 595 596 597 598 599 600 } 601 602 603 599 if (done) 600 break; 601 602 *p = TR_PATH_DELIMITER; 603 p++; 604 pp = p; 605 } 606 607 tr_free (path); 608 return 0; 604 609 } 605 610 … … 607 612 tr_buildPath (const char *first_element, ...) 608 613 { 609 size_t bufLen = 0; 610 const char * element; 611 char * buf; 612 char * pch; 613 va_list vl; 614 615 /* pass 1: allocate enough space for the string */ 616 va_start (vl, first_element); 617 element = first_element; 618 while (element) { 619 bufLen += strlen (element) + 1; 620 element = va_arg (vl, const char*); 621 } 622 pch = buf = tr_new (char, bufLen); 623 va_end (vl); 624 625 /* pass 2: build the string piece by piece */ 626 va_start (vl, first_element); 627 element = first_element; 628 while (element) { 629 const size_t elementLen = strlen (element); 630 memcpy (pch, element, elementLen); 631 pch += elementLen; 632 *pch++ = TR_PATH_DELIMITER; 633 element = va_arg (vl, const char*); 634 } 635 va_end (vl); 636 637 /* terminate the string. if nonempty, eat the unwanted trailing slash */ 638 if (pch != buf) 639 --pch; 640 *pch++ = '\0'; 641 642 /* sanity checks & return */ 643 assert (pch - buf == (off_t)bufLen); 644 return buf; 614 const char * element; 615 char * buf; 616 char * pch; 617 va_list vl; 618 size_t bufLen = 0; 619 620 /* pass 1: allocate enough space for the string */ 621 va_start (vl, first_element); 622 element = first_element; 623 while (element) 624 { 625 bufLen += strlen (element) + 1; 626 element = va_arg (vl, const char*); 627 } 628 pch = buf = tr_new (char, bufLen); 629 va_end (vl); 630 631 /* pass 2: build the string piece by piece */ 632 va_start (vl, first_element); 633 element = first_element; 634 while (element) 635 { 636 const size_t elementLen = strlen (element); 637 memcpy (pch, element, elementLen); 638 pch += elementLen; 639 *pch++ = TR_PATH_DELIMITER; 640 element = va_arg (vl, const char*); 641 } 642 va_end (vl); 643 644 /* terminate the string. if nonempty, eat the unwanted trailing slash */ 645 if (pch != buf) 646 --pch; 647 *pch++ = '\0'; 648 649 /* sanity checks & return */ 650 assert (pch - buf == (off_t)bufLen); 651 return buf; 645 652 } 646 653 … … 654 661 tr_fileExists (const char * filename, time_t * mtime) 655 662 { 656 657 658 659 660 661 662 663 struct stat sb; 664 const bool ok = !stat (filename, &sb); 665 666 if (ok && (mtime != NULL)) 667 *mtime = TR_STAT_MTIME (sb); 668 669 return ok; 663 670 } 664 671 … … 670 677 evbuffer_free_to_str (struct evbuffer * buf) 671 678 { 672 673 674 675 676 677 679 const size_t n = evbuffer_get_length (buf); 680 char * ret = tr_new (char, n + 1); 681 evbuffer_copyout (buf, ret, n); 682 evbuffer_free (buf); 683 ret[n] = '\0'; 684 return ret; 678 685 } 679 686 … … 681 688 tr_strdup (const void * in) 682 689 { 683 690 return tr_strndup (in, in ? (int)strlen ((const char *)in) : 0); 684 691 } 685 692 … … 687 694 tr_strndup (const void * in, int len) 688 695 { 689 690 691 692 { 693 694 } 695 696 { 697 698 699 700 } 701 702 696 char * out = NULL; 697 698 if (len < 0) 699 { 700 out = tr_strdup (in); 701 } 702 else if (in) 703 { 704 out = tr_malloc (len + 1); 705 memcpy (out, in, len); 706 out[len] = '\0'; 707 } 708 709 return out; 703 710 } 704 711 … … 708 715 { 709 716 #ifdef HAVE_MEMMEM 710 717 return memmem (haystack, haystacklen, needle, needlelen); 711 718 #else 712 size_t i; 713 if (!needlelen) 714 return haystack; 715 if (needlelen > haystacklen || !haystack || !needle) 716 return NULL; 717 for (i=0; i<=haystacklen-needlelen; ++i) 718 if (!memcmp (haystack+i, needle, needlelen)) 719 return haystack+i; 719 size_t i; 720 if (!needlelen) 721 return haystack; 722 if (needlelen > haystacklen || !haystack || !needle) 720 723 return NULL; 724 for (i=0; i<=haystacklen-needlelen; ++i) 725 if (!memcmp (haystack+i, needle, needlelen)) 726 return haystack+i; 727 return NULL; 721 728 #endif 722 729 } … … 725 732 tr_strdup_printf (const char * fmt, ...) 726 733 { 727 va_list ap; 728 char * ret; 729 size_t len; 730 char statbuf[2048]; 731 732 va_start (ap, fmt); 733 len = evutil_vsnprintf (statbuf, sizeof (statbuf), fmt, ap); 734 va_end (ap); 735 if (len < sizeof (statbuf)) 736 ret = tr_strndup (statbuf, len); 737 else { 738 ret = tr_new (char, len + 1); 739 va_start (ap, fmt); 740 evutil_vsnprintf (ret, len + 1, fmt, ap); 741 va_end (ap); 742 } 743 744 return ret; 734 va_list ap; 735 char * ret; 736 size_t len; 737 char statbuf[2048]; 738 739 va_start (ap, fmt); 740 len = evutil_vsnprintf (statbuf, sizeof (statbuf), fmt, ap); 741 va_end (ap); 742 743 if (len < sizeof (statbuf)) 744 { 745 ret = tr_strndup (statbuf, len); 746 } 747 else 748 { 749 ret = tr_new (char, len + 1); 750 va_start (ap, fmt); 751 evutil_vsnprintf (ret, len + 1, fmt, ap); 752 va_end (ap); 753 } 754 755 return ret; 745 756 } 746 757 … … 748 759 tr_strerror (int i) 749 760 { 750 const char * ret = strerror (i); 751 752 if (ret == NULL) 753 ret = "Unknown Error"; 754 return ret; 761 const char * ret = strerror (i); 762 763 if (ret == NULL) 764 ret = "Unknown Error"; 765 766 return ret; 755 767 } 756 768 … … 758 770 tr_strcmp0 (const char * str1, const char * str2) 759 771 { 760 761 762 763 772 if (str1 && str2) return strcmp (str1, str2); 773 if (str1) return 1; 774 if (str2) return -1; 775 return 0; 764 776 } 765 777 … … 773 785 { 774 786 #ifdef HAVE_STRSEP 775 787 return strsep (str, delims); 776 788 #else 777 778 779 if (*str == NULL) {780 /* No more tokens */781 return NULL; 782 }783 784 token = *str;785 while (**str != '\0') {786 if (strchr (delims, **str) != NULL){787 789 char *token; 790 791 if (*str == NULL) /* no more tokens */ 792 return NULL; 793 794 token = *str; 795 while (**str != '\0') 796 { 797 if (strchr (delims, **str) != NULL) 798 { 799 **str = '\0'; 788 800 (*str)++; 789 801 return token; … … 792 804 } 793 805 794 /* There is not another token */795 796 797 806 /* there is not another token */ 807 *str = NULL; 808 809 return token; 798 810 #endif 799 811 } … … 802 814 tr_strstrip (char * str) 803 815 { 804 805 { 806 807 808 809 810 811 812 813 814 815 816 817 818 } 819 820 816 if (str != NULL) 817 { 818 size_t pos; 819 size_t len = strlen (str); 820 821 while (len && isspace (str[len - 1])) 822 --len; 823 824 for (pos = 0; pos < len && isspace (str[pos]);) 825 ++pos; 826 827 len -= pos; 828 memmove (str, str + pos, len); 829 str[len] = '\0'; 830 } 831 832 return str; 821 833 } 822 834 … … 824 836 tr_str_has_suffix (const char *str, const char *suffix) 825 837 { 826 827 828 829 830 831 832 833 834 835 836 837 838 839 838 size_t str_len; 839 size_t suffix_len; 840 841 if (!str) 842 return false; 843 if (!suffix) 844 return true; 845 846 str_len = strlen (str); 847 suffix_len = strlen (suffix); 848 if (str_len < suffix_len) 849 return false; 850 851 return !evutil_ascii_strncasecmp (str + str_len - suffix_len, suffix, suffix_len); 840 852 } 841 853 … … 847 859 tr_time_msec (void) 848 860 { 849 850 851 852 861 struct timeval tv; 862 863 gettimeofday (&tv, NULL); 864 return (uint64_t) tv.tv_sec * 1000 + (tv.tv_usec / 1000); 853 865 } 854 866 … … 857 869 { 858 870 #ifdef WIN32 859 871 Sleep ((DWORD)msec); 860 872 #else 861 862 863 864 873 struct timespec ts; 874 ts.tv_sec = msec / 1000; 875 ts.tv_nsec = (msec % 1000) * 1000000; 876 nanosleep (&ts, NULL); 865 877 #endif 866 878 } … … 873 885 tr_snprintf (char * buf, size_t buflen, const char * fmt, ...) 874 886 { 875 intlen;876 877 878 879 880 881 887 int len; 888 va_list args; 889 890 va_start (args, fmt); 891 len = evutil_vsnprintf (buf, buflen, fmt, args); 892 va_end (args); 893 return len; 882 894 } 883 895 … … 891 903 { 892 904 #ifdef HAVE_STRLCPY 893 905 return strlcpy (dst, src, siz); 894 906 #else 895 896 897 898 899 900 901 902 903 904 { 905 907 char * d = dst; 908 const char *s = src; 909 size_t n = siz; 910 911 assert (s); 912 assert (d); 913 914 /* Copy as many bytes as will fit */ 915 if (n != 0) 916 { 917 while (--n != 0) 906 918 { 907 908 919 if ((*d++ = *s++) == '\0') 920 break; 909 921 } 910 922 } 911 923 912 913 914 { 915 916 917 918 919 } 920 921 924 /* Not enough room in dst, add NUL and traverse rest of src */ 925 if (n == 0) 926 { 927 if (siz != 0) 928 *d = '\0'; /* NUL-terminate dst */ 929 while (*s++) 930 ; 931 } 932 933 return s - (char*)src - 1; /* count does not include NUL */ 922 934 #endif 923 935 } … … 930 942 tr_getRatio (uint64_t numerator, uint64_t denominator) 931 943 { 932 933 934 935 936 937 938 939 940 941 944 double ratio; 945 946 if (denominator > 0) 947 ratio = numerator / (double)denominator; 948 else if (numerator > 0) 949 ratio = TR_RATIO_INF; 950 else 951 ratio = TR_RATIO_NA; 952 953 return ratio; 942 954 } 943 955 … … 945 957 tr_sha1_to_hex (char * out, const uint8_t * sha1) 946 958 { 947 948 949 950 951 { 952 953 954 955 } 956 957 959 int i; 960 static const char hex[] = "0123456789abcdef"; 961 962 for (i=0; i<20; ++i) 963 { 964 const unsigned int val = *sha1++; 965 *out++ = hex[val >> 4]; 966 *out++ = hex[val & 0xf]; 967 } 968 969 *out = '\0'; 958 970 } 959 971 … … 961 973 tr_hex_to_sha1 (uint8_t * out, const char * in) 962 974 { 963 964 965 966 967 { 968 969 970 975 int i; 976 static const char hex[] = "0123456789abcdef"; 977 978 for (i=0; i<20; ++i) 979 { 980 const int hi = strchr (hex, tolower (*in++)) - hex; 981 const int lo = strchr (hex, tolower (*in++)) - hex; 982 *out++ = (uint8_t)((hi<<4) | lo); 971 983 } 972 984 } … … 979 991 isValidURLChars (const char * url, int url_len) 980 992 { 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 993 const char * c; 994 const char * end; 995 static const char * rfc2396_valid_chars = 996 "abcdefghijklmnopqrstuvwxyz" /* lowalpha */ 997 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */ 998 "0123456789" /* digit */ 999 "-_.!~*'()" /* mark */ 1000 ";/?:@&=+$," /* reserved */ 1001 "<>#%<\"" /* delims */ 1002 "{}|\\^[]`"; /* unwise */ 1003 1004 if (url == NULL) 1005 return false; 1006 1007 for (c=url, end=c+url_len; c && *c && c!=end; ++c) 1008 if (!strchr (rfc2396_valid_chars, *c)) 1009 return false; 1010 1011 return true; 1000 1012 } 1001 1013 … … 1004 1016 tr_urlIsValidTracker (const char * url) 1005 1017 { 1006 1007 1008 1009 { 1010 1011 } 1012 1013 { 1014 1015 1016 1017 1018 1019 } 1020 1021 1018 bool valid; 1019 1020 if (url == NULL) 1021 { 1022 valid = false; 1023 } 1024 else 1025 { 1026 const int len = strlen (url); 1027 1028 valid = isValidURLChars (url, len) 1029 && !tr_urlParse (url, len, NULL, NULL, NULL, NULL) 1030 && (!memcmp (url,"http://",7) || !memcmp (url,"https://",8) || !memcmp (url,"udp://",6)); 1031 } 1032 1033 return valid; 1022 1034 } 1023 1035 … … 1026 1038 tr_urlIsValid (const char * url, int url_len) 1027 1039 { 1028 1029 1030 1031 { 1032 1033 } 1034 1035 { 1036 1037 1038 1039 1040 1041 1042 } 1043 1044 1040 bool valid; 1041 1042 if (url == NULL) 1043 { 1044 valid = false; 1045 } 1046 else 1047 { 1048 if (url_len < 0) 1049 url_len = strlen (url); 1050 1051 valid = isValidURLChars (url, url_len) 1052 && !tr_urlParse (url, url_len, NULL, NULL, NULL, NULL) 1053 && (!memcmp (url,"http://",7) || !memcmp (url,"https://",8) || !memcmp (url,"ftp://",6) || !memcmp (url,"sftp://",7)); 1054 } 1055 1056 return valid; 1045 1057 } 1046 1058 … … 1048 1060 tr_addressIsIP (const char * str) 1049 1061 { 1050 1051 1062 tr_address tmp; 1063 return tr_address_from_string (&tmp, str); 1052 1064 } 1053 1065 … … 1060 1072 char ** setme_path) 1061 1073 { 1062 int err; 1063 int port = 0; 1064 int n; 1065 char * tmp; 1066 char * pch; 1067 size_t host_len; 1068 size_t protocol_len; 1069 const char * host = NULL; 1070 const char * protocol = NULL; 1071 const char * path = NULL; 1072 1073 tmp = tr_strndup (url_in, len); 1074 if ((pch = strstr (tmp, "://"))) 1075 { 1076 *pch = '\0'; 1077 protocol = tmp; 1078 protocol_len = pch - protocol; 1079 pch += 3; 1080 /*fprintf (stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch);*/ 1081 if ((n = strcspn (pch, ":/"))) 1074 int err; 1075 int port = 0; 1076 int n; 1077 char * tmp; 1078 char * pch; 1079 size_t host_len; 1080 size_t protocol_len; 1081 const char * host = NULL; 1082 const char * protocol = NULL; 1083 const char * path = NULL; 1084 1085 tmp = tr_strndup (url_in, len); 1086 if ((pch = strstr (tmp, "://"))) 1087 { 1088 *pch = '\0'; 1089 protocol = tmp; 1090 protocol_len = pch - protocol; 1091 pch += 3; 1092 if ((n = strcspn (pch, ":/"))) 1082 1093 { 1083 const int havePort = pch[n] == ':'; 1084 host = pch; 1085 host_len = n; 1086 pch += n; 1087 if (pch && *pch) 1088 *pch++ = '\0'; 1089 /*fprintf (stderr, "host is [%s]... what's left is [%s]\n", host, pch);*/ 1090 if (havePort) 1094 const int havePort = pch[n] == ':'; 1095 host = pch; 1096 host_len = n; 1097 pch += n; 1098 if (pch && *pch) 1099 *pch++ = '\0'; 1100 if (havePort) 1091 1101 { 1092 char * end; 1093 port = strtol (pch, &end, 10); 1094 pch = end; 1095 /*fprintf (stderr, "port is [%d]... what's left is [%s]\n", port, pch);*/ 1102 char * end; 1103 port = strtol (pch, &end, 10); 1104 pch = end; 1096 1105 } 1097 path = pch; 1098 /*fprintf (stderr, "path is [%s]\n", path);*/ 1106 path = pch; 1099 1107 } 1100 1108 } 1101 1109 1102 err = !host || !path || !protocol; 1103 1104 if (!err && !port) 1105 { 1106 if (!strcmp (protocol, "udp")) port = 80; 1107 else if (!strcmp (protocol, "ftp")) port = 21; 1108 else if (!strcmp (protocol, "sftp")) port = 22; 1109 else if (!strcmp (protocol, "http")) port = 80; 1110 else if (!strcmp (protocol, "https")) port = 443; 1111 } 1112 1113 if (!err) 1114 { 1115 if (setme_protocol) *setme_protocol = tr_strndup (protocol, protocol_len); 1116 1117 if (setme_host){ ((char*)host)[-3] = ':'; *setme_host = 1118 tr_strndup (host, host_len); } 1119 if (setme_path){ if (!*path) *setme_path = tr_strdup ("/"); 1120 else if (path[0] == '/') *setme_path = tr_strdup (path); 1121 else { ((char*)path)[-1] = '/'; *setme_path = tr_strdup (path - 1); } } 1122 if (setme_port) *setme_port = port; 1123 } 1124 1125 1126 tr_free (tmp); 1127 return err; 1110 err = !host || !path || !protocol; 1111 1112 if (!err && !port) 1113 { 1114 if (!strcmp (protocol, "udp")) port = 80; 1115 else if (!strcmp (protocol, "ftp")) port = 21; 1116 else if (!strcmp (protocol, "sftp")) port = 22; 1117 else if (!strcmp (protocol, "http")) port = 80; 1118 else if (!strcmp (protocol, "https")) port = 443; 1119 } 1120 1121 if (!err) 1122 { 1123 if (setme_protocol) *setme_protocol = tr_strndup (protocol, protocol_len); 1124 1125 if (setme_host){ ((char*)host)[-3] = ':'; *setme_host = 1126 tr_strndup (host, host_len); } 1127 1128 if (setme_path){ if (!*path) *setme_path = tr_strdup ("/"); 1129 else if (path[0] == '/') *setme_path = tr_strdup (path); 1130 else { ((char*)path)[-1] = '/'; *setme_path = tr_strdup (path - 1); } } 1131 1132 if (setme_port) *setme_port = port; 1133 } 1134 1135 1136 tr_free (tmp); 1137 return err; 1128 1138 } 1129 1139 … … 1138 1148 tr_base64_encode (const void * input, int length, int * setme_len) 1139 1149 { 1140 1141 1142 1143 1144 { 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1150 int retlen = 0; 1151 char * ret = NULL; 1152 1153 if (input != NULL) 1154 { 1155 BIO * b64; 1156 BIO * bmem; 1157 BUF_MEM * bptr; 1158 1159 if (length < 1) 1160 length = (int)strlen (input); 1161 1162 bmem = BIO_new (BIO_s_mem ()); 1163 b64 = BIO_new (BIO_f_base64 ()); 1164 BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL); 1165 b64 = BIO_push (b64, bmem); 1166 BIO_write (b64, input, length); 1157 1167 (void) BIO_flush (b64); 1158 1159 1160 1161 1162 } 1163 1164 1165 1166 1167 1168 BIO_get_mem_ptr (b64, &bptr); 1169 ret = tr_strndup (bptr->data, bptr->length); 1170 retlen = bptr->length; 1171 BIO_free_all (b64); 1172 } 1173 1174 if (setme_len) 1175 *setme_len = retlen; 1176 1177 return ret; 1168 1178 } 1169 1179 … … 1173 1183 int * setme_len) 1174 1184 { 1175 1176 BIO *b64;1177 BIO *bmem;1178 intretlen;1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 { 1190 1191 1192 1193 1194 1195 1196 1197 } 1198 1199 1200 1201 1202 1203 1185 char * ret; 1186 BIO * b64; 1187 BIO * bmem; 1188 int retlen; 1189 1190 if (length < 1) 1191 length = strlen (input); 1192 1193 ret = tr_new0 (char, length); 1194 b64 = BIO_new (BIO_f_base64 ()); 1195 bmem = BIO_new_mem_buf ((unsigned char*)input, length); 1196 bmem = BIO_push (b64, bmem); 1197 retlen = BIO_read (bmem, ret, length); 1198 if (!retlen) 1199 { 1200 /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */ 1201 BIO_free_all (bmem); 1202 b64 = BIO_new (BIO_f_base64 ()); 1203 BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL); 1204 bmem = BIO_new_mem_buf ((unsigned char*)input, length); 1205 bmem = BIO_push (b64, bmem); 1206 retlen = BIO_read (bmem, ret, length); 1207 } 1208 1209 if (setme_len) 1210 *setme_len = retlen; 1211 1212 BIO_free_all (bmem); 1213 return ret; 1204 1214 } 1205 1215 … … 1214 1224 size_t nmemb) 1215 1225 { 1216 1217 1218 1219 1220 1226 char * a = array; 1227 1228 memmove (a + sizeof_element * index_to_remove, 1229 a + sizeof_element * (index_to_remove + 1), 1230 sizeof_element * (--nmemb - index_to_remove)); 1221 1231 } 1222 1232 … … 1229 1239 bool * exact_match) 1230 1240 { 1231 size_t first = 0; 1232 const char * cbase = base; 1233 bool exact = false; 1234 1235 while (nmemb != 0) 1236 { 1237 const size_t half = nmemb / 2; 1238 const size_t middle = first + half; 1239 const int c = compar (key, cbase + size*middle); 1240 1241 if (c <= 0) { 1242 if (c == 0) 1243 exact = true; 1244 nmemb = half; 1245 } else { 1246 first = middle + 1; 1247 nmemb = nmemb - half - 1; 1241 size_t first = 0; 1242 const char * cbase = base; 1243 bool exact = false; 1244 1245 while (nmemb != 0) 1246 { 1247 const size_t half = nmemb / 2; 1248 const size_t middle = first + half; 1249 const int c = compar (key, cbase + size*middle); 1250 1251 if (c <= 0) 1252 { 1253 if (c == 0) 1254 exact = true; 1255 nmemb = half; 1248 1256 } 1249 } 1250 1251 *exact_match = exact; 1252 1253 return first; 1257 else 1258 { 1259 first = middle + 1; 1260 nmemb = nmemb - half - 1; 1261 } 1262 } 1263 1264 *exact_match = exact; 1265 return first; 1254 1266 } 1255 1267 … … 1367 1379 strip_non_utf8 (const char * in, size_t inlen) 1368 1380 { 1369 1370 1371 1372 1373 1374 { 1375 1376 1377 1378 1379 1380 1381 } 1382 1383 1384 1385 1381 const char * end; 1382 const char zero = '\0'; 1383 struct evbuffer * buf = evbuffer_new (); 1384 1385 while (!tr_utf8_validate (in, inlen, &end)) 1386 { 1387 const int good_len = end - in; 1388 1389 evbuffer_add (buf, in, good_len); 1390 inlen -= (good_len + 1); 1391 in += (good_len + 1); 1392 evbuffer_add (buf, "?", 1); 1393 } 1394 1395 evbuffer_add (buf, in, inlen); 1396 evbuffer_add (buf, &zero, 1); 1397 return evbuffer_free_to_str (buf); 1386 1398 } 1387 1399 … … 1389 1401 to_utf8 (const char * in, size_t inlen) 1390 1402 { 1391 1403 char * ret = NULL; 1392 1404 1393 1405 #ifdef HAVE_ICONV_OPEN 1394 int i; 1395 const char * encodings[] = { "CURRENT", "ISO-8859-15" }; 1396 const int encoding_count = sizeof (encodings) / sizeof (encodings[1]); 1397 const size_t buflen = inlen*4 + 10; 1398 char * out = tr_new (char, buflen); 1399 1400 for (i=0; !ret && i<encoding_count; ++i) 1401 { 1402 char * inbuf = (char*) in; 1403 char * outbuf = out; 1404 size_t inbytesleft = inlen; 1405 size_t outbytesleft = buflen; 1406 const char * test_encoding = encodings[i]; 1407 1408 iconv_t cd = iconv_open ("UTF-8", test_encoding); 1409 if (cd != (iconv_t)-1) { 1410 if (iconv (cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft) != (size_t)-1) 1411 ret = tr_strndup (out, buflen-outbytesleft); 1412 iconv_close (cd); 1406 int i; 1407 const char * encodings[] = { "CURRENT", "ISO-8859-15" }; 1408 const int encoding_count = sizeof (encodings) / sizeof (encodings[1]); 1409 const size_t buflen = inlen*4 + 10; 1410 char * out = tr_new (char, buflen); 1411 1412 for (i=0; !ret && i<encoding_count; ++i) 1413 { 1414 char * inbuf = (char*) in; 1415 char * outbuf = out; 1416 size_t inbytesleft = inlen; 1417 size_t outbytesleft = buflen; 1418 const char * test_encoding = encodings[i]; 1419 1420 iconv_t cd = iconv_open ("UTF-8", test_encoding); 1421 if (cd != (iconv_t)-1) 1422 { 1423 if (iconv (cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft) != (size_t)-1) 1424 ret = tr_strndup (out, buflen-outbytesleft); 1425 iconv_close (cd); 1413 1426 } 1414 1427 } 1415 1428 1416 1417 #endif 1418 1419 1420 1421 1422 1429 tr_free (out); 1430 #endif 1431 1432 if (ret == NULL) 1433 ret = strip_non_utf8 (in, inlen); 1434 1435 return ret; 1423 1436 } 1424 1437 … … 1426 1439 tr_utf8clean (const char * str, int max_len) 1427 1440 { 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 char * ret; 1442 const char * end; 1443 1444 if (max_len < 0) 1445 max_len = (int) strlen (str); 1446 1447 if (tr_utf8_validate (str, max_len, &end)) 1448 ret = tr_strndup (str, max_len); 1449 else 1450 ret = to_utf8 (str, max_len); 1451 1452 assert (tr_utf8_validate (ret, -1, NULL)); 1453 return ret; 1441 1454 } 1442 1455 … … 1447 1460 struct number_range 1448 1461 { 1449 1450 1462 int low; 1463 int high; 1451 1464 }; 1452 1465 … … 1458 1471 parseNumberSection (const char * str, int len, struct number_range * setme) 1459 1472 { 1460 long a, b; 1461 bool success; 1462 char * end; 1463 const int error = errno; 1464 char * tmp = tr_strndup (str, len); 1465 1466 errno = 0; 1467 a = b = strtol (tmp, &end, 10); 1468 if (errno || (end == tmp)) { 1473 long a, b; 1474 bool success; 1475 char * end; 1476 const int error = errno; 1477 char * tmp = tr_strndup (str, len); 1478 1479 errno = 0; 1480 a = b = strtol (tmp, &end, 10); 1481 if (errno || (end == tmp)) 1482 { 1483 success = false; 1484 } 1485 else if (*end != '-') 1486 { 1487 success = true; 1488 } 1489 else 1490 { 1491 const char * pch = end + 1; 1492 b = strtol (pch, &end, 10); 1493 if (errno || (pch == end)) 1469 1494 success = false; 1470 } else if (*end != '-') { 1495 else if (*end) /* trailing data */ 1496 success = false; 1497 else 1471 1498 success = true; 1472 } else { 1473 const char * pch = end + 1; 1474 b = strtol (pch, &end, 10); 1475 if (errno || (pch == end)) 1476 success = false; 1477 else if (*end) /* trailing data */ 1478 success = false; 1479 else 1480 success = true; 1481 } 1482 tr_free (tmp); 1483 1484 setme->low = MIN (a, b); 1485 setme->high = MAX (a, b); 1486 1487 errno = error; 1488 return success; 1499 } 1500 1501 tr_free (tmp); 1502 1503 setme->low = MIN (a, b); 1504 setme->high = MAX (a, b); 1505 1506 errno = error; 1507 return success; 1489 1508 } 1490 1509 … … 1492 1511 compareInt (const void * va, const void * vb) 1493 1512 { 1494 1495 1496 1513 const int a = * (const int *)va; 1514 const int b = * (const int *)vb; 1515 return a - b; 1497 1516 } 1498 1517 … … 1507 1526 tr_parseNumberRange (const char * str_in, int len, int * setmeCount) 1508 1527 { 1509 int n = 0; 1510 int * uniq = NULL; 1511 char * str = tr_strndup (str_in, len); 1512 const char * walk; 1513 tr_list * ranges = NULL; 1514 bool success = true; 1515 1516 walk = str; 1517 while (walk && *walk && success) { 1518 struct number_range range; 1519 const char * pch = strchr (walk, ','); 1520 if (pch) { 1521 success = parseNumberSection (walk, pch-walk, &range); 1522 walk = pch + 1; 1523 } else { 1524 success = parseNumberSection (walk, strlen (walk), &range); 1525 walk += strlen (walk); 1528 int n = 0; 1529 int * uniq = NULL; 1530 char * str = tr_strndup (str_in, len); 1531 const char * walk; 1532 tr_list * ranges = NULL; 1533 bool success = true; 1534 1535 walk = str; 1536 while (walk && *walk && success) 1537 { 1538 struct number_range range; 1539 const char * pch = strchr (walk, ','); 1540 if (pch) 1541 { 1542 success = parseNumberSection (walk, pch-walk, &range); 1543 walk = pch + 1; 1526 1544 } 1527 if (success) 1528 tr_list_append (&ranges, tr_memdup (&range, sizeof (struct number_range))); 1529 } 1530 1531 if (!success) 1532 { 1533 *setmeCount = 0; 1534 uniq = NULL; 1535 } 1536 else 1537 { 1538 int i; 1539 int n2; 1540 tr_list * l; 1541 int * sorted = NULL; 1542 1543 /* build a sorted number array */ 1544 n = n2 = 0; 1545 for (l=ranges; l!=NULL; l=l->next) { 1546 const struct number_range * r = l->data; 1547 n += r->high + 1 - r->low; 1545 else 1546 { 1547 success = parseNumberSection (walk, strlen (walk), &range); 1548 walk += strlen (walk); 1548 1549 } 1549 sorted = tr_new (int, n); 1550 for (l=ranges; l!=NULL; l=l->next) { 1551 const struct number_range * r = l->data; 1552 int i; 1553 for (i=r->low; i<=r->high; ++i) 1554 sorted[n2++] = i; 1550 if (success) 1551 tr_list_append (&ranges, tr_memdup (&range, sizeof (struct number_range))); 1552 } 1553 1554 if (!success) 1555 { 1556 *setmeCount = 0; 1557 uniq = NULL; 1558 } 1559 else 1560 { 1561 int i; 1562 int n2; 1563 tr_list * l; 1564 int * sorted = NULL; 1565 1566 /* build a sorted number array */ 1567 n = n2 = 0; 1568 for (l=ranges; l!=NULL; l=l->next) 1569 { 1570 const struct number_range * r = l->data; 1571 n += r->high + 1 - r->low; 1555 1572 } 1556 qsort (sorted, n, sizeof (int), compareInt); 1557 assert (n == n2); 1558 1559 /* remove duplicates */ 1560 uniq = tr_new (int, n); 1561 for (i=n=0; i<n2; ++i) 1562 if (!n || uniq[n-1] != sorted[i]) 1563 uniq[n++] = sorted[i]; 1564 1565 tr_free (sorted); 1566 } 1567 1568 /* cleanup */ 1569 tr_list_free (&ranges, tr_free); 1570 tr_free (str); 1571 1572 /* return the result */ 1573 *setmeCount = n; 1574 return uniq; 1573 sorted = tr_new (int, n); 1574 for (l=ranges; l!=NULL; l=l->next) 1575 { 1576 int i; 1577 const struct number_range * r = l->data; 1578 for (i=r->low; i<=r->high; ++i) 1579 sorted[n2++] = i; 1580 } 1581 qsort (sorted, n, sizeof (int), compareInt); 1582 assert (n == n2); 1583 1584 /* remove duplicates */ 1585 uniq = tr_new (int, n); 1586 for (i=n=0; i<n2; ++i) 1587 if (!n || uniq[n-1] != sorted[i]) 1588 uniq[n++] = sorted[i]; 1589 1590 tr_free (sorted); 1591 } 1592 1593 /* cleanup */ 1594 tr_list_free (&ranges, tr_free); 1595 tr_free (str); 1596 1597 /* return the result */ 1598 *setmeCount = n; 1599 return uniq; 1575 1600 } 1576 1601 … … 1582 1607 tr_truncd (double x, int precision) 1583 1608 { 1584 1585 1586 1587 1588 1589 1590 1609 char * pt; 1610 char buf[128]; 1611 const int max_precision = (int) log10 (1.0 / DBL_EPSILON) - 1; 1612 tr_snprintf (buf, sizeof (buf), "%.*f", max_precision, x); 1613 if ((pt = strstr (buf, localeconv ()->decimal_point))) 1614 pt[precision ? precision+1 : 0] = '\0'; 1615 return atof (buf); 1591 1616 } 1592 1617 … … 1595 1620 tr_strtruncd (char * buf, double x, int precision, size_t buflen) 1596 1621 { 1597 1598 1622 tr_snprintf (buf, buflen, "%.*f", precision, tr_truncd (x, precision)); 1623 return buf; 1599 1624 } 1600 1625 … … 1602 1627 tr_strpercent (char * buf, double x, size_t buflen) 1603 1628 { 1604 if (x < 10.0) 1605 tr_strtruncd (buf, x, 2, buflen); 1606 else if (x < 100.0) 1607 tr_strtruncd (buf, x, 1, buflen); 1608 else 1609 tr_strtruncd (buf, x, 0, buflen); 1610 return buf; 1629 if (x < 10.0) 1630 tr_strtruncd (buf, x, 2, buflen); 1631 else if (x < 100.0) 1632 tr_strtruncd (buf, x, 1, buflen); 1633 else 1634 tr_strtruncd (buf, x, 0, buflen); 1635 1636 return buf; 1611 1637 } 1612 1638 … … 1614 1640 tr_strratio (char * buf, size_t buflen, double ratio, const char * infinity) 1615 1641 { 1616 if ((int)ratio == TR_RATIO_NA) 1617 tr_strlcpy (buf, _("None"), buflen); 1618 else if ((int)ratio == TR_RATIO_INF) 1619 tr_strlcpy (buf, infinity, buflen); 1620 else 1621 tr_strpercent (buf, ratio, buflen); 1622 return buf; 1642 if ((int)ratio == TR_RATIO_NA) 1643 tr_strlcpy (buf, _("None"), buflen); 1644 else if ((int)ratio == TR_RATIO_INF) 1645 tr_strlcpy (buf, infinity, buflen); 1646 else 1647 tr_strpercent (buf, ratio, buflen); 1648 1649 return buf; 1623 1650 } 1624 1651 … … 1630 1657 tr_moveFile (const char * oldpath, const char * newpath, bool * renamed) 1631 1658 { 1632 int in; 1633 int out; 1634 char * buf; 1635 struct stat st; 1636 off_t bytesLeft; 1637 const size_t buflen = 1024 * 128; /* 128 KiB buffer */ 1638 1639 /* make sure the old file exists */ 1640 if (stat (oldpath, &st)) { 1641 const int err = errno; 1642 errno = err; 1643 return -1; 1644 } 1645 if (!S_ISREG (st.st_mode)) { 1646 errno = ENOENT; 1647 return -1; 1648 } 1649 bytesLeft = st.st_size; 1650 1651 /* make sure the target directory exists */ 1652 { 1653 char * newdir = tr_dirname (newpath); 1654 int i = tr_mkdirp (newdir, 0777); 1655 tr_free (newdir); 1656 if (i) 1657 return i; 1658 } 1659 1660 /* they might be on the same filesystem... */ 1661 { 1662 const int i = rename (oldpath, newpath); 1663 if (renamed != NULL) 1664 *renamed = i == 0; 1665 if (!i) 1666 return 0; 1667 } 1668 1669 /* copy the file */ 1670 in = tr_open_file_for_scanning (oldpath); 1671 out = tr_open_file_for_writing (newpath); 1672 buf = tr_valloc (buflen); 1673 while (bytesLeft > 0) 1674 { 1675 ssize_t bytesWritten; 1676 const off_t bytesThisPass = MIN (bytesLeft, (off_t)buflen); 1677 const int numRead = read (in, buf, bytesThisPass); 1678 if (numRead < 0) 1679 break; 1680 bytesWritten = write (out, buf, numRead); 1681 if (bytesWritten < 0) 1682 break; 1683 bytesLeft -= bytesWritten; 1684 } 1685 1686 /* cleanup */ 1687 tr_free (buf); 1688 tr_close_file (out); 1689 tr_close_file (in); 1690 if (bytesLeft != 0) 1691 return -1; 1692 1693 unlink (oldpath); 1694 return 0; 1659 int in; 1660 int out; 1661 char * buf; 1662 struct stat st; 1663 off_t bytesLeft; 1664 const size_t buflen = 1024 * 128; /* 128 KiB buffer */ 1665 1666 /* make sure the old file exists */ 1667 if (stat (oldpath, &st)) 1668 { 1669 const int err = errno; 1670 errno = err; 1671 return -1; 1672 } 1673 if (!S_ISREG (st.st_mode)) 1674 { 1675 errno = ENOENT; 1676 return -1; 1677 } 1678 bytesLeft = st.st_size; 1679 1680 /* make sure the target directory exists */ 1681 { 1682 char * newdir = tr_dirname (newpath); 1683 int i = tr_mkdirp (newdir, 0777); 1684 tr_free (newdir); 1685 if (i) 1686 return i; 1687 } 1688 1689 /* they might be on the same filesystem... */ 1690 { 1691 const int i = rename (oldpath, newpath); 1692 if (renamed != NULL) 1693 *renamed = i == 0; 1694 if (!i) 1695 return 0; 1696 } 1697 1698 /* copy the file */ 1699 in = tr_open_file_for_scanning (oldpath); 1700 out = tr_open_file_for_writing (newpath); 1701 buf = tr_valloc (buflen); 1702 while (bytesLeft > 0) 1703 { 1704 ssize_t bytesWritten; 1705 const off_t bytesThisPass = MIN (bytesLeft, (off_t)buflen); 1706 const int numRead = read (in, buf, bytesThisPass); 1707 if (numRead < 0) 1708 break; 1709 bytesWritten = write (out, buf, numRead); 1710 if (bytesWritten < 0) 1711 break; 1712 bytesLeft -= bytesWritten; 1713 } 1714 1715 /* cleanup */ 1716 tr_free (buf); 1717 tr_close_file (out); 1718 tr_close_file (in); 1719 if (bytesLeft != 0) 1720 return -1; 1721 1722 unlink (oldpath); 1723 return 0; 1695 1724 } 1696 1725 … … 1698 1727 tr_is_same_file (const char * filename1, const char * filename2) 1699 1728 { 1700 1701 1702 1703 1704 1705 1729 struct stat sb1, sb2; 1730 1731 return !stat (filename1, &sb1) 1732 && !stat (filename2, &sb2) 1733 && (sb1.st_dev == sb2.st_dev) 1734 && (sb1.st_ino == sb2.st_ino); 1706 1735 } 1707 1736 … … 1713 1742 tr_valloc (size_t bufLen) 1714 1743 { 1715 size_t allocLen; 1716 void * buf = NULL; 1717 static size_t pageSize = 0; 1718 1719 if (!pageSize) { 1744 size_t allocLen; 1745 void * buf = NULL; 1746 static size_t pageSize = 0; 1747 1748 if (!pageSize) 1749 { 1720 1750 #ifdef HAVE_GETPAGESIZE 1721 1751 pageSize = (size_t) getpagesize (); 1722 1752 #else /* guess */ 1723 1724 #endif 1725 } 1726 1727 1728 1729 1753 pageSize = 4096; 1754 #endif 1755 } 1756 1757 allocLen = pageSize; 1758 while (allocLen < bufLen) 1759 allocLen += pageSize; 1730 1760 1731 1761 #ifdef HAVE_POSIX_MEMALIGN 1732 1733 1734 1762 if (!buf) 1763 if (posix_memalign (&buf, pageSize, allocLen)) 1764 buf = NULL; /* just retry with valloc/malloc */ 1735 1765 #endif 1736 1766 #ifdef HAVE_VALLOC 1737 1738 1739 #endif 1740 1741 1742 1743 1767 if (!buf) 1768 buf = valloc (allocLen); 1769 #endif 1770 if (!buf) 1771 buf = tr_malloc (allocLen); 1772 1773 return buf; 1744 1774 } 1745 1775 … … 1748 1778 { 1749 1779 #ifdef WIN32 1750 1751 1752 1753 1780 /* From a message to the Mingw-msys list, Jun 2, 2005 by Mark Junker. */ 1781 if (GetFullPathNameA (path, TR_PATH_MAX, resolved_path, NULL) == 0) 1782 return NULL; 1783 return resolved_path; 1754 1784 #else 1755 1785 return realpath (path, resolved_path); 1756 1786 #endif 1757 1787 } … … 1765 1795 { 1766 1796 #ifdef HAVE_HTONLL 1767 1797 return htonll (x); 1768 1798 #else 1769 1770 1771 1772 1773 1774 1799 /* fallback code by bdonlan at 1800 * http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c/875505#875505 */ 1801 union { uint32_t lx[2]; uint64_t llx; } u; 1802 u.lx[0] = htonl (x >> 32); 1803 u.lx[1] = htonl (x & 0xFFFFFFFFULL); 1804 return u.llx; 1775 1805 #endif 1776 1806 } … … 1780 1810 { 1781 1811 #ifdef HAVE_NTOHLL 1782 1812 return ntohll (x); 1783 1813 #else 1784 1785 1786 1787 1788 1814 /* fallback code by bdonlan at 1815 * http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c/875505#875505 */ 1816 union { uint32_t lx[2]; uint64_t llx; } u; 1817 u.llx = x; 1818 return ((uint64_t)ntohl (u.lx[0]) << 32) | (uint64_t)ntohl (u.lx[1]); 1789 1819 #endif 1790 1820 } … … 1798 1828 struct formatter_unit 1799 1829 { 1800 1801 1830 char * name; 1831 int64_t value; 1802 1832 }; 1803 1833 1804 1834 struct formatter_units 1805 1835 { 1806 1836 struct formatter_unit units[4]; 1807 1837 }; 1808 1838 … … 1815 1845 const char * gb, const char * tb) 1816 1846 { 1817 uint64_t value = kilo; 1818 units->units[TR_FMT_KB].name = tr_strdup (kb); 1819 units->units[TR_FMT_KB].value = value; 1820 1821 value *= kilo; 1822 units->units[TR_FMT_MB].name = tr_strdup (mb); 1823 units->units[TR_FMT_MB].value = value; 1824 1825 value *= kilo; 1826 units->units[TR_FMT_GB].name = tr_strdup (gb); 1827 units->units[TR_FMT_GB].value = value; 1828 1829 value *= kilo; 1830 units->units[TR_FMT_TB].name = tr_strdup (tb); 1831 units->units[TR_FMT_TB].value = value; 1847 uint64_t value; 1848 1849 value = kilo; 1850 units->units[TR_FMT_KB].name = tr_strdup (kb); 1851 units->units[TR_FMT_KB].value = value; 1852 1853 value *= kilo; 1854 units->units[TR_FMT_MB].name = tr_strdup (mb); 1855 units->units[TR_FMT_MB].value = value; 1856 1857 value *= kilo; 1858 units->units[TR_FMT_GB].name = tr_strdup (gb); 1859 units->units[TR_FMT_GB].value = value; 1860 1861 value *= kilo; 1862 units->units[TR_FMT_TB].name = tr_strdup (tb); 1863 units->units[TR_FMT_TB].value = value; 1832 1864 } 1833 1865 … … 1836 1868 char * buf, int64_t bytes, size_t buflen) 1837 1869 { 1838 int precision; 1839 double value; 1840 const char * units; 1841 const struct formatter_unit * unit; 1842 1843 if (bytes < u->units[1].value) unit = &u->units[0]; 1844 else if (bytes < u->units[2].value) unit = &u->units[1]; 1845 else if (bytes < u->units[3].value) unit = &u->units[2]; 1846 else unit = &u->units[3]; 1847 1848 value = (double)bytes / unit->value; 1849 units = unit->name; 1850 if (unit->value == 1) 1851 precision = 0; 1852 else if (value < 100) 1853 precision = 2; 1854 else 1855 precision = 1; 1856 tr_snprintf (buf, buflen, "%.*f %s", precision, value, units); 1857 return buf; 1870 int precision; 1871 double value; 1872 const char * units; 1873 const struct formatter_unit * unit; 1874 1875 if (bytes < u->units[1].value) unit = &u->units[0]; 1876 else if (bytes < u->units[2].value) unit = &u->units[1]; 1877 else if (bytes < u->units[3].value) unit = &u->units[2]; 1878 else unit = &u->units[3]; 1879 1880 value = (double)bytes / unit->value; 1881 units = unit->name; 1882 1883 if (unit->value == 1) 1884 precision = 0; 1885 else if (value < 100) 1886 precision = 2; 1887 else 1888 precision = 1; 1889 1890 tr_snprintf (buf, buflen, "%.*f %s", precision, value, units); 1891 return buf; 1858 1892 } 1859 1893 … … 1865 1899 const char * gb, const char * tb) 1866 1900 { 1867 1901 formatter_init (&size_units, kilo, kb, mb, gb, tb); 1868 1902 } 1869 1903 … … 1871 1905 tr_formatter_size_B (char * buf, int64_t bytes, size_t buflen) 1872 1906 { 1873 1907 return formatter_get_size_str (&size_units, buf, bytes, buflen); 1874 1908 } 1875 1909 … … 1883 1917 const char * gb, const char * tb) 1884 1918 { 1885 1886 1919 tr_speed_K = kilo; 1920 formatter_init (&speed_units, kilo, kb, mb, gb, tb); 1887 1921 } 1888 1922 … … 1890 1924 tr_formatter_speed_KBps (char * buf, double KBps, size_t buflen) 1891 1925 { 1892 const double K = speed_units.units[TR_FMT_KB].value; 1893 double speed = KBps; 1894 1895 if (speed <= 999.95) /* 0.0 KB to 999.9 KB */ 1896 tr_snprintf (buf, buflen, "%d %s", (int)speed, speed_units.units[TR_FMT_KB].name); 1897 else { 1898 speed /= K; 1899 if (speed <= 99.995) /* 0.98 MB to 99.99 MB */ 1900 tr_snprintf (buf, buflen, "%.2f %s", speed, speed_units.units[TR_FMT_MB].name); 1901 else if (speed <= 999.95) /* 100.0 MB to 999.9 MB */ 1902 tr_snprintf (buf, buflen, "%.1f %s", speed, speed_units.units[TR_FMT_MB].name); 1903 else { 1904 speed /= K; 1905 tr_snprintf (buf, buflen, "%.1f %s", speed, speed_units.units[TR_FMT_GB].name); 1906 } 1907 } 1908 1909 return buf; 1926 const double K = speed_units.units[TR_FMT_KB].value; 1927 double speed = KBps; 1928 1929 if (speed <= 999.95) /* 0.0 KB to 999.9 KB */ 1930 { 1931 tr_snprintf (buf, buflen, "%d %s", (int)speed, speed_units.units[TR_FMT_KB].name); 1932 } 1933 else 1934 { 1935 speed /= K; 1936 1937 if (speed <= 99.995) /* 0.98 MB to 99.99 MB */ 1938 tr_snprintf (buf, buflen, "%.2f %s", speed, speed_units.units[TR_FMT_MB].name); 1939 else if (speed <= 999.95) /* 100.0 MB to 999.9 MB */ 1940 tr_snprintf (buf, buflen, "%.1f %s", speed, speed_units.units[TR_FMT_MB].name); 1941 else 1942 tr_snprintf (buf, buflen, "%.1f %s", speed/K, speed_units.units[TR_FMT_GB].name); 1943 } 1944 1945 return buf; 1910 1946 } 1911 1947 … … 1919 1955 const char * gb, const char * tb) 1920 1956 { 1921 1922 1957 tr_mem_K = kilo; 1958 formatter_init (&mem_units, kilo, kb, mb, gb, tb); 1923 1959 } 1924 1960 … … 1926 1962 tr_formatter_mem_B (char * buf, int64_t bytes_per_second, size_t buflen) 1927 1963 { 1928 1964 return formatter_get_size_str (&mem_units, buf, bytes_per_second, buflen); 1929 1965 } 1930 1966 -
trunk/libtransmission/web.c
r13625 r13863 39 39 enum 40 40 { 41 41 THREADFUNC_MAX_SLEEP_MSEC = 1000, 42 42 }; 43 43 44 44 #if 0 45 45 #define dbgmsg(...) \ 46 47 48 49 46 do { \ 47 fprintf (stderr, __VA_ARGS__); \ 48 fprintf (stderr, "\n"); \ 49 } while (0) 50 50 #else 51 51 #define dbgmsg(...) \ 52 53 54 55 52 do { \ 53 if (tr_deepLoggingIsActive ()) \ 54 tr_deepLog (__FILE__, __LINE__, "web", __VA_ARGS__); \ 55 } while (0) 56 56 #endif 57 57 … … 62 62 struct tr_web_task 63 63 { 64 65 66 67 68 69 70 71 72 73 74 75 76 77 64 long code; 65 long timeout_secs; 66 bool did_connect; 67 bool did_timeout; 68 struct evbuffer * response; 69 struct evbuffer * freebuf; 70 char * url; 71 char * range; 72 char * cookies; 73 tr_session * session; 74 tr_web_done_func * done_func; 75 void * done_func_user_data; 76 CURL * curl_easy; 77 struct tr_web_task * next; 78 78 }; 79 79 … … 81 81 task_free (struct tr_web_task * task) 82 82 { 83 84 85 86 87 88 83 if (task->freebuf) 84 evbuffer_free (task->freebuf); 85 tr_free (task->cookies); 86 tr_free (task->range); 87 tr_free (task->url); 88 tr_free (task); 89 89 } 90 90 … … 95 95 struct tr_web 96 96 { 97 98 99 100 101 102 103 97 bool curl_verbose; 98 bool curl_ssl_verify; 99 const char * curl_ca_bundle; 100 int close_mode; 101 struct tr_web_task * tasks; 102 tr_lock * taskLock; 103 char * cookie_filename; 104 104 }; 105 105 … … 111 111 writeFunc (void * ptr, size_t size, size_t nmemb, void * vtask) 112 112 { 113 114 115 116 117 113 const size_t byteCount = size * nmemb; 114 struct tr_web_task * task = vtask; 115 evbuffer_add (task->response, ptr, byteCount); 116 dbgmsg ("wrote %zu bytes to task %p's buffer", byteCount, task); 117 return byteCount; 118 118 } 119 119 … … 122 122 sockoptfunction (void * vtask, curl_socket_t fd, curlsocktype purpose UNUSED) 123 123 { 124 125 126 127 128 129 130 { 131 132 133 134 135 } 136 137 138 124 struct tr_web_task * task = vtask; 125 const bool isScrape = strstr (task->url, "scrape") != NULL; 126 const bool isAnnounce = strstr (task->url, "announce") != NULL; 127 128 /* announce and scrape requests have tiny payloads. */ 129 if (isScrape || isAnnounce) 130 { 131 const int sndbuf = 1024; 132 const int rcvbuf = isScrape ? 2048 : 3072; 133 setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof (sndbuf)); 134 setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof (rcvbuf)); 135 } 136 137 /* return nonzero if this function encountered an error */ 138 return 0; 139 139 } 140 140 #endif … … 143 143 getTimeoutFromURL (const struct tr_web_task * task) 144 144 { 145 146 147 148 149 150 151 152 153 145 long timeout; 146 const tr_session * session = task->session; 147 148 if (!session || session->isClosed) timeout = 20L; 149 else if (strstr (task->url, "scrape") != NULL) timeout = 30L; 150 else if (strstr (task->url, "announce") != NULL) timeout = 90L; 151 else timeout = 240L; 152 153 return timeout; 154 154 } 155 155 … … 157 157 createEasy (tr_session * s, struct tr_web * web, struct tr_web_task * task) 158 158 { 159 160 161 162 163 164 165 166 167 168 169 170 171 159 bool is_default_value; 160 const tr_address * addr; 161 CURL * e = task->curl_easy = curl_easy_init (); 162 163 task->timeout_secs = getTimeoutFromURL (task); 164 165 curl_easy_setopt (e, CURLOPT_AUTOREFERER, 1L); 166 curl_easy_setopt (e, CURLOPT_COOKIEFILE, web->cookie_filename); 167 curl_easy_setopt (e, CURLOPT_ENCODING, "gzip;q=1.0, deflate, identity"); 168 curl_easy_setopt (e, CURLOPT_FOLLOWLOCATION, 1L); 169 curl_easy_setopt (e, CURLOPT_MAXREDIRS, -1L); 170 curl_easy_setopt (e, CURLOPT_NOSIGNAL, 1L); 171 curl_easy_setopt (e, CURLOPT_PRIVATE, task); 172 172 #ifdef USE_LIBCURL_SOCKOPT 173 174 173 curl_easy_setopt (e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction); 174 curl_easy_setopt (e, CURLOPT_SOCKOPTDATA, task); 175 175 #endif 176 if (web->curl_ssl_verify) 177 curl_easy_setopt (e, CURLOPT_CAINFO, web->curl_ca_bundle); 178 else { 179 curl_easy_setopt (e, CURLOPT_SSL_VERIFYHOST, 0L); 180 curl_easy_setopt (e, CURLOPT_SSL_VERIFYPEER, 0L); 181 } 182 curl_easy_setopt (e, CURLOPT_TIMEOUT, task->timeout_secs); 183 curl_easy_setopt (e, CURLOPT_URL, task->url); 184 curl_easy_setopt (e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING); 185 curl_easy_setopt (e, CURLOPT_VERBOSE, (long)(web->curl_verbose?1:0)); 186 curl_easy_setopt (e, CURLOPT_WRITEDATA, task); 187 curl_easy_setopt (e, CURLOPT_WRITEFUNCTION, writeFunc); 188 189 if (((addr = tr_sessionGetPublicAddress (s, TR_AF_INET, &is_default_value))) && !is_default_value) 190 curl_easy_setopt (e, CURLOPT_INTERFACE, tr_address_to_string (addr)); 191 else if (((addr = tr_sessionGetPublicAddress (s, TR_AF_INET6, &is_default_value))) && !is_default_value) 192 curl_easy_setopt (e, CURLOPT_INTERFACE, tr_address_to_string (addr)); 193 194 if (task->cookies != NULL) 195 curl_easy_setopt (e, CURLOPT_COOKIE, task->cookies); 196 197 if (task->range != NULL) { 198 curl_easy_setopt (e, CURLOPT_RANGE, task->range); 199 /* don't bother asking the server to compress webseed fragments */ 200 curl_easy_setopt (e, CURLOPT_ENCODING, "identity"); 201 } 202 203 return e; 176 if (web->curl_ssl_verify) 177 { 178 curl_easy_setopt (e, CURLOPT_CAINFO, web->curl_ca_bundle); 179 } 180 else 181 { 182 curl_easy_setopt (e, CURLOPT_SSL_VERIFYHOST, 0L); 183 curl_easy_setopt (e, CURLOPT_SSL_VERIFYPEER, 0L); 184 } 185 curl_easy_setopt (e, CURLOPT_TIMEOUT, task->timeout_secs); 186 curl_easy_setopt (e, CURLOPT_URL, task->url); 187 curl_easy_setopt (e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING); 188 curl_easy_setopt (e, CURLOPT_VERBOSE, (long)(web->curl_verbose?1:0)); 189 curl_easy_setopt (e, CURLOPT_WRITEDATA, task); 190 curl_easy_setopt (e, CURLOPT_WRITEFUNCTION, writeFunc); 191 192 if (((addr = tr_sessionGetPublicAddress (s, TR_AF_INET, &is_default_value))) && !is_default_value) 193 curl_easy_setopt (e, CURLOPT_INTERFACE, tr_address_to_string (addr)); 194 else if (((addr = tr_sessionGetPublicAddress (s, TR_AF_INET6, &is_default_value))) && !is_default_value) 195 curl_easy_setopt (e, CURLOPT_INTERFACE, tr_address_to_string (addr)); 196 197 if (task->cookies != NULL) 198 curl_easy_setopt (e, CURLOPT_COOKIE, task->cookies); 199 200 if (task->range != NULL) 201 { 202 curl_easy_setopt (e, CURLOPT_RANGE, task->range); 203 /* don't bother asking the server to compress webseed fragments */ 204 curl_easy_setopt (e, CURLOPT_ENCODING, "identity"); 205 } 206 207 return e; 204 208 } 205 209 … … 211 215 task_finish_func (void * vtask) 212 216 { 213 214 215 216 217 218 219 220 221 222 223 224 225 217 struct tr_web_task * task = vtask; 218 dbgmsg ("finished web task %p; got %ld", task, task->code); 219 220 if (task->done_func != NULL) 221 task->done_func (task->session, 222 task->did_connect, 223 task->did_timeout, 224 task->code, 225 evbuffer_pullup (task->response, -1), 226 evbuffer_get_length (task->response), 227 task->done_func_user_data); 228 229 task_free (task); 226 230 } 227 231 … … 238 242 void * done_func_user_data) 239 243 { 240 241 242 244 return tr_webRunWithBuffer (session, url, range, cookies, 245 done_func, done_func_user_data, 246 NULL); 243 247 } 244 248 … … 252 256 struct evbuffer * buffer) 253 257 { 254 struct tr_web * web = session->web; 255 256 if (web != NULL) 257 { 258 struct tr_web_task * task = tr_new0 (struct tr_web_task, 1); 259 260 task->session = session; 261 task->url = tr_strdup (url); 262 task->range = tr_strdup (range); 263 task->cookies = tr_strdup (cookies); 264 task->done_func = done_func; 265 task->done_func_user_data = done_func_user_data; 266 task->response = buffer ? buffer : evbuffer_new (); 267 task->freebuf = buffer ? NULL : task->response; 268 269 tr_lockLock (web->taskLock); 270 task->next = web->tasks; 271 web->tasks = task; 272 tr_lockUnlock (web->taskLock); 273 return task; 274 } 275 return NULL; 258 struct tr_web * web = session->web; 259 260 if (web != NULL) 261 { 262 struct tr_web_task * task = tr_new0 (struct tr_web_task, 1); 263 264 task->session = session; 265 task->url = tr_strdup (url); 266 task->range = tr_strdup (range); 267 task->cookies = tr_strdup (cookies); 268 task->done_func = done_func; 269 task->done_func_user_data = done_func_user_data; 270 task->response = buffer ? buffer : evbuffer_new (); 271 task->freebuf = buffer ? NULL : task->response; 272 273 tr_lockLock (web->taskLock); 274 task->next = web->tasks; 275 web->tasks = task; 276 tr_lockUnlock (web->taskLock); 277 return task; 278 } 279 280 return NULL; 276 281 } 277 282 … … 290 295 { 291 296 #ifdef WIN32 292 293 { 294 295 296 } 297 298 299 300 { 301 302 303 304 297 if (!r_fd_set->fd_count && !w_fd_set->fd_count && !c_fd_set->fd_count) 298 { 299 const long int msec = t->tv_sec*1000 + t->tv_usec/1000; 300 tr_wait_msec (msec); 301 } 302 else if (select (0, r_fd_set->fd_count ? r_fd_set : NULL, 303 w_fd_set->fd_count ? w_fd_set : NULL, 304 c_fd_set->fd_count ? c_fd_set : NULL, t) < 0) 305 { 306 char errstr[512]; 307 const int e = EVUTIL_SOCKET_ERROR (); 308 tr_net_strerror (errstr, sizeof (errstr), e); 309 dbgmsg ("Error: select (%d) %s", e, errstr); 305 310 } 306 311 #else 307 312 select (nfds, r_fd_set, w_fd_set, c_fd_set, t); 308 313 #endif 309 314 } … … 312 317 tr_webThreadFunc (void * vsession) 313 318 { 314 CURLM * multi; 315 struct tr_web * web; 316 int taskCount = 0; 317 struct tr_web_task * task; 318 tr_session * session = vsession; 319 320 /* try to enable ssl for https support; but if that fails, 321 * try a plain vanilla init */ 322 if (curl_global_init (CURL_GLOBAL_SSL)) 323 curl_global_init (0); 324 325 web = tr_new0 (struct tr_web, 1); 326 web->close_mode = ~0; 327 web->taskLock = tr_lockNew (); 328 web->tasks = NULL; 329 web->curl_verbose = getenv ("TR_CURL_VERBOSE") != NULL; 330 web->curl_ssl_verify = getenv ("TR_CURL_SSL_VERIFY") != NULL; 331 web->curl_ca_bundle = getenv ("CURL_CA_BUNDLE"); 332 if (web->curl_ssl_verify) { 333 tr_ninf ("web", "will verify tracker certs using envvar CURL_CA_BUNDLE: %s", 334 web->curl_ca_bundle == NULL ? "none" : web->curl_ca_bundle); 335 tr_ninf ("web", "NB: this only works if you built against libcurl with openssl or gnutls, NOT nss"); 336 tr_ninf ("web", "NB: invalid certs will show up as 'Could not connect to tracker' like many other errors"); 337 } 338 web->cookie_filename = tr_buildPath (session->configDir, "cookies.txt", NULL); 339 340 multi = curl_multi_init (); 341 session->web = web; 342 343 for (;;) 344 { 345 long msec; 346 int unused; 347 CURLMsg * msg; 348 CURLMcode mcode; 349 350 if (web->close_mode == TR_WEB_CLOSE_NOW) 351 break; 352 if ((web->close_mode == TR_WEB_CLOSE_WHEN_IDLE) && (web->tasks == NULL)) 353 break; 354 355 /* add tasks from the queue */ 356 tr_lockLock (web->taskLock); 357 while (web->tasks != NULL) 319 CURLM * multi; 320 struct tr_web * web; 321 int taskCount = 0; 322 struct tr_web_task * task; 323 tr_session * session = vsession; 324 325 /* try to enable ssl for https support; but if that fails, 326 * try a plain vanilla init */ 327 if (curl_global_init (CURL_GLOBAL_SSL)) 328 curl_global_init (0); 329 330 web = tr_new0 (struct tr_web, 1); 331 web->close_mode = ~0; 332 web->taskLock = tr_lockNew (); 333 web->tasks = NULL; 334 web->curl_verbose = getenv ("TR_CURL_VERBOSE") != NULL; 335 web->curl_ssl_verify = getenv ("TR_CURL_SSL_VERIFY") != NULL; 336 web->curl_ca_bundle = getenv ("CURL_CA_BUNDLE"); 337 if (web->curl_ssl_verify) 338 { 339 tr_ninf ("web", "will verify tracker certs using envvar CURL_CA_BUNDLE: %s", 340 web->curl_ca_bundle == NULL ? "none" : web->curl_ca_bundle); 341 tr_ninf ("web", "NB: this only works if you built against libcurl with openssl or gnutls, NOT nss"); 342 tr_ninf ("web", "NB: invalid certs will show up as 'Could not connect to tracker' like many other errors"); 343 } 344 web->cookie_filename = tr_buildPath (session->configDir, "cookies.txt", NULL); 345 346 multi = curl_multi_init (); 347 session->web = web; 348 349 for (;;) 350 { 351 long msec; 352 int unused; 353 CURLMsg * msg; 354 CURLMcode mcode; 355 356 if (web->close_mode == TR_WEB_CLOSE_NOW) 357 break; 358 if ((web->close_mode == TR_WEB_CLOSE_WHEN_IDLE) && (web->tasks == NULL)) 359 break; 360 361 /* add tasks from the queue */ 362 tr_lockLock (web->taskLock); 363 while (web->tasks != NULL) 358 364 { 359 360 361 362 363 364 365 366 367 365 /* pop the task */ 366 task = web->tasks; 367 web->tasks = task->next; 368 task->next = NULL; 369 370 dbgmsg ("adding task to curl: [%s]", task->url); 371 curl_multi_add_handle (multi, createEasy (session, web, task)); 372 /*fprintf (stderr, "adding a task.. taskCount is now %d\n", taskCount);*/ 373 ++taskCount; 368 374 } 369 tr_lockUnlock (web->taskLock); 370 371 /* maybe wait a little while before calling curl_multi_perform () */ 372 msec = 0; 373 curl_multi_timeout (multi, &msec); 374 if (msec < 0) 375 tr_lockUnlock (web->taskLock); 376 377 /* maybe wait a little while before calling curl_multi_perform () */ 378 msec = 0; 379 curl_multi_timeout (multi, &msec); 380 if (msec < 0) 381 msec = THREADFUNC_MAX_SLEEP_MSEC; 382 if (session->isClosed) 383 msec = 100; /* on shutdown, call perform () more frequently */ 384 if (msec > 0) 385 { 386 int usec; 387 int max_fd; 388 struct timeval t; 389 fd_set r_fd_set, w_fd_set, c_fd_set; 390 391 max_fd = 0; 392 FD_ZERO (&r_fd_set); 393 FD_ZERO (&w_fd_set); 394 FD_ZERO (&c_fd_set); 395 curl_multi_fdset (multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd); 396 397 if (msec > THREADFUNC_MAX_SLEEP_MSEC) 375 398 msec = THREADFUNC_MAX_SLEEP_MSEC; 376 if (session->isClosed) 377 msec = 100; /* on shutdown, call perform () more frequently */ 378 if (msec > 0) 399 400 usec = msec * 1000; 401 t.tv_sec = usec / 1000000; 402 t.tv_usec = usec % 1000000; 403 tr_select (max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t); 404 } 405 406 /* call curl_multi_perform () */ 407 do 408 mcode = curl_multi_perform (multi, &unused); 409 while (mcode == CURLM_CALL_MULTI_PERFORM); 410 411 /* pump completed tasks from the multi */ 412 while ((msg = curl_multi_info_read (multi, &unused))) 379 413 { 380 int usec; 381 int max_fd; 382 struct timeval t; 383 fd_set r_fd_set, w_fd_set, c_fd_set; 384 385 max_fd = 0; 386 FD_ZERO (&r_fd_set); 387 FD_ZERO (&w_fd_set); 388 FD_ZERO (&c_fd_set); 389 curl_multi_fdset (multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd); 390 391 if (msec > THREADFUNC_MAX_SLEEP_MSEC) 392 msec = THREADFUNC_MAX_SLEEP_MSEC; 393 394 usec = msec * 1000; 395 t.tv_sec = usec / 1000000; 396 t.tv_usec = usec % 1000000; 397 tr_select (max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t); 398 } 399 400 /* call curl_multi_perform () */ 401 do { 402 mcode = curl_multi_perform (multi, &unused); 403 } while (mcode == CURLM_CALL_MULTI_PERFORM); 404 405 /* pump completed tasks from the multi */ 406 while ((msg = curl_multi_info_read (multi, &unused))) 407 { 408 if ((msg->msg == CURLMSG_DONE) && (msg->easy_handle != NULL)) 414 if ((msg->msg == CURLMSG_DONE) && (msg->easy_handle != NULL)) 409 415 { 410 double total_time; 411 struct tr_web_task * task; 412 long req_bytes_sent; 413 CURL * e = msg->easy_handle; 414 curl_easy_getinfo (e, CURLINFO_PRIVATE, (void*)&task); 415 curl_easy_getinfo (e, CURLINFO_RESPONSE_CODE, &task->code); 416 curl_easy_getinfo (e, CURLINFO_REQUEST_SIZE, &req_bytes_sent); 417 curl_easy_getinfo (e, CURLINFO_TOTAL_TIME, &total_time); 418 task->did_connect = task->code>0 || req_bytes_sent>0; 419 task->did_timeout = !task->code && (total_time >= task->timeout_secs); 420 curl_multi_remove_handle (multi, e); 421 curl_easy_cleanup (e); 422 /*fprintf (stderr, "removing a completed task.. taskCount is now %d (response code: %d, response len: %d)\n", taskCount, (int)task->code, (int)evbuffer_get_length (task->response));*/ 423 tr_runInEventThread (task->session, task_finish_func, task); 424 --taskCount; 416 double total_time; 417 struct tr_web_task * task; 418 long req_bytes_sent; 419 CURL * e = msg->easy_handle; 420 curl_easy_getinfo (e, CURLINFO_PRIVATE, (void*)&task); 421 curl_easy_getinfo (e, CURLINFO_RESPONSE_CODE, &task->code); 422 curl_easy_getinfo (e, CURLINFO_REQUEST_SIZE, &req_bytes_sent); 423 curl_easy_getinfo (e, CURLINFO_TOTAL_TIME, &total_time); 424 task->did_connect = task->code>0 || req_bytes_sent>0; 425 task->did_timeout = !task->code && (total_time >= task->timeout_secs); 426 curl_multi_remove_handle (multi, e); 427 curl_easy_cleanup (e); 428 tr_runInEventThread (task->session, task_finish_func, task); 429 --taskCount; 425 430 } 426 431 } 427 432 } 428 433 429 /* Discard any remaining tasks. 430 * This is rare, but can happen on shutdown with unresponsive trackers. */ 431 while (web->tasks != NULL) { 432 task = web->tasks; 433 web->tasks = task->next; 434 dbgmsg ("Discarding task \"%s\"", task->url); 435 task_free (task); 436 } 437 438 /* cleanup */ 439 curl_multi_cleanup (multi); 440 tr_lockFree (web->taskLock); 441 tr_free (web->cookie_filename); 442 tr_free (web); 443 session->web = NULL; 434 /* Discard any remaining tasks. 435 * This is rare, but can happen on shutdown with unresponsive trackers. */ 436 while (web->tasks != NULL) 437 { 438 task = web->tasks; 439 web->tasks = task->next; 440 dbgmsg ("Discarding task \"%s\"", task->url); 441 task_free (task); 442 } 443 444 /* cleanup */ 445 curl_multi_cleanup (multi); 446 tr_lockFree (web->taskLock); 447 tr_free (web->cookie_filename); 448 tr_free (web); 449 session->web = NULL; 444 450 } 445 451 … … 447 453 tr_webInit (tr_session * session) 448 454 { 449 455 tr_threadNew (tr_webThreadFunc, session); 450 456 } 451 457 … … 453 459 tr_webClose (tr_session * session, tr_web_close_mode close_mode) 454 460 { 455 456 { 457 458 459 460 461 461 if (session->web != NULL) 462 { 463 session->web->close_mode = close_mode; 464 465 if (close_mode == TR_WEB_CLOSE_NOW) 466 while (session->web != NULL) 467 tr_wait_msec (100); 462 468 } 463 469 } … … 466 472 tr_webGetTaskInfo (struct tr_web_task * task, tr_web_task_info info, void * dst) 467 473 { 468 474 curl_easy_getinfo (task->curl_easy, (CURLINFO) info, dst); 469 475 } 470 476 … … 477 483 tr_webGetResponseStr (long code) 478 484 { 479 480 { 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 485 switch (code) 486 { 487 case 0: return "No Response"; 488 case 101: return "Switching Protocols"; 489 case 200: return "OK"; 490 case 201: return "Created"; 491 case 202: return "Accepted"; 492 case 203: return "Non-Authoritative Information"; 493 case 204: return "No Content"; 494 case 205: return "Reset Content"; 495 case 206: return "Partial Content"; 496 case 300: return "Multiple Choices"; 497 case 301: return "Moved Permanently"; 498 case 302: return "Found"; 499 case 303: return "See Other"; 500 case 304: return "Not Modified"; 501 case 305: return "Use Proxy"; 502 case 306: return " (Unused)"; 503 case 307: return "Temporary Redirect"; 504 case 400: return "Bad Request"; 505 case 401: return "Unauthorized"; 506 case 402: return "Payment Required"; 507 case 403: return "Forbidden"; 508 case 404: return "Not Found"; 509 case 405: return "Method Not Allowed"; 510 case 406: return "Not Acceptable"; 511 case 407: return "Proxy Authentication Required"; 512 case 408: return "Request Timeout"; 513 case 409: return "Conflict"; 514 case 410: return "Gone"; 515 case 411: return "Length Required"; 516 case 412: return "Precondition Failed"; 517 case 413: return "Request Entity Too Large"; 518 case 414: return "Request-URI Too Long"; 519 case 415: return "Unsupported Media Type"; 520 case 416: return "Requested Range Not Satisfiable"; 521 case 417: return "Expectation Failed"; 522 case 500: return "Internal Server Error"; 523 case 501: return "Not Implemented"; 524 case 502: return "Bad Gateway"; 525 case 503: return "Service Unavailable"; 526 case 504: return "Gateway Timeout"; 527 case 505: return "HTTP Version Not Supported"; 528 default: return "Unknown Error"; 523 529 } 524 530 } … … 526 532 void 527 533 tr_http_escape (struct evbuffer * out, 528 const char * str, int len, bool escape_slashes) 529 { 530 const char * end; 531 532 if ((len < 0) && (str != NULL)) 533 len = strlen (str); 534 535 for (end=str+len; str && str!=end; ++str) { 536 if ((*str == ',') 537 || (*str == '-') 538 || (*str == '.') 539 || (('0' <= *str) && (*str <= '9')) 540 || (('A' <= *str) && (*str <= 'Z')) 541 || (('a' <= *str) && (*str <= 'z')) 542 || ((*str == '/') && (!escape_slashes))) 543 evbuffer_add_printf (out, "%c", *str); 544 else 545 evbuffer_add_printf (out, "%%%02X", (unsigned)(*str&0xFF)); 534 const char * str, 535 int len, 536 bool escape_slashes) 537 { 538 const char * end; 539 540 if ((len < 0) && (str != NULL)) 541 len = strlen (str); 542 543 for (end=str+len; str && str!=end; ++str) 544 { 545 if ((*str == ',') || (*str == '-') 546 || (*str == '.') 547 || (('0' <= *str) && (*str <= '9')) 548 || (('A' <= *str) && (*str <= 'Z')) 549 || (('a' <= *str) && (*str <= 'z')) 550 || ((*str == '/') && (!escape_slashes))) 551 evbuffer_add_printf (out, "%c", *str); 552 else 553 evbuffer_add_printf (out, "%%%02X", (unsigned)(*str&0xFF)); 546 554 } 547 555 } … … 550 558 tr_http_unescape (const char * str, int len) 551 559 { 552 553 554 555 560 char * tmp = curl_unescape (str, len); 561 char * ret = tr_strdup (tmp); 562 curl_free (tmp); 563 return ret; 556 564 } 557 565 … … 559 567 is_rfc2396_alnum (uint8_t ch) 560 568 { 561 562 563 564 565 566 567 569 return ('0' <= ch && ch <= '9') 570 || ('A' <= ch && ch <= 'Z') 571 || ('a' <= ch && ch <= 'z') 572 || ch == '.' 573 || ch == '-' 574 || ch == '_' 575 || ch == '~'; 568 576 } 569 577 … … 571 579 tr_http_escape_sha1 (char * out, const uint8_t * sha1_digest) 572 580 { 573 574 575 576 577 578 579 580 581 582 583 } 581 const uint8_t * in = sha1_digest; 582 const uint8_t * end = in + SHA_DIGEST_LENGTH; 583 584 while (in != end) 585 if (is_rfc2396_alnum (*in)) 586 *out++ = (char) *in++; 587 else 588 out += tr_snprintf (out, 4, "%%%02x", (unsigned int)*in++); 589 590 *out = '\0'; 591 }
Note: See TracChangeset
for help on using the changeset viewer.